summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-12 21:30:25 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-12 21:30:25 +0000
commit321ad87b01c1e040f3f121044f8c255ca5548b30 (patch)
tree50a7575b7ee9d0ec0498395a6557af7b74e6ecfd
parentdb2ff4b4607eb2a54b30ea9c4b8248e7a1cebfe5 (diff)
downloadchromium_src-321ad87b01c1e040f3f121044f8c255ca5548b30.zip
chromium_src-321ad87b01c1e040f3f121044f8c255ca5548b30.tar.gz
chromium_src-321ad87b01c1e040f3f121044f8c255ca5548b30.tar.bz2
Working rudimentary audio in Pepper.
BUG=28292 TEST=none Patch by neb@chromium.org Original review: http://codereview.chromium.org/524006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36043 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.cc142
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.h54
-rw-r--r--third_party/npapi/bindings/npapi_extensions.h85
-rw-r--r--webkit/glue/media/video_renderer_impl.cc16
-rw-r--r--webkit/glue/media/video_renderer_impl.h3
-rw-r--r--webkit/glue/plugins/npapi_extension_thunk.cc85
-rw-r--r--webkit/glue/plugins/webplugin_audio_device_delegate.h56
-rw-r--r--webkit/glue/webplugin_delegate.h4
-rw-r--r--webkit/tools/pepper_test_plugin/plugin_object.cc42
-rw-r--r--webkit/tools/pepper_test_plugin/plugin_object.h3
10 files changed, 489 insertions, 1 deletions
diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc
index 3680804..c5e93ad 100644
--- a/chrome/renderer/webplugin_delegate_pepper.cc
+++ b/chrome/renderer/webplugin_delegate_pepper.cc
@@ -564,6 +564,148 @@ NPError WebPluginDelegatePepper::Device3DMapBuffer(
return NPERR_NO_ERROR;
}
+NPError WebPluginDelegatePepper::DeviceAudioQueryCapability(int32 capability,
+ int32* value) {
+ // TODO(neb,cpu) implement QueryCapability
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioQueryConfig(
+ const NPDeviceContextAudioConfig* request,
+ NPDeviceContextAudioConfig* obtain) {
+ // TODO(neb,cpu) implement QueryConfig
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioInitializeContext(
+ const NPDeviceContextAudioConfig* config,
+ NPDeviceContextAudio* context) {
+
+ if (!render_view_) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ scoped_refptr<AudioMessageFilter> filter =
+ render_view_->audio_message_filter();
+ ViewHostMsg_Audio_CreateStream params;
+
+ params.format = AudioManager::AUDIO_PCM_LINEAR;
+ params.channels = config->outputChannelMap;
+ params.sample_rate = config->sampleRate;
+ switch (config->sampleType) {
+ case NPAudioSampleTypeInt16:
+ params.bits_per_sample = 16;
+ break;
+ case NPAudioSampleTypeFloat32:
+ params.bits_per_sample = 32;
+ break;
+ default:
+ return NPERR_INVALID_PARAM;
+ }
+
+ context->config = *config;
+ params.packet_size = config->sampleFrameCount * config->outputChannelMap
+ * (params.bits_per_sample >> 3);
+ LOG(INFO) << "Initializing Pepper Audio Context (" <<
+ config->sampleFrameCount << "Hz, " << params.bits_per_sample <<
+ " bits, " << config->outputChannelMap << "channels";
+
+ // TODO(neb): figure out if this number is grounded in reality
+ params.buffer_capacity = params.packet_size * 3;
+
+ // TODO(neb): keep these guys tracked somewhere so we can delete them
+ // even if the plugin doesn't
+ AudioStream *audio = new AudioStream(this);
+ audio->Initialize(filter, params, context);
+ return NPERR_NO_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioSetStateContext(
+ NPDeviceContextAudio* context,
+ int32 state,
+ int32 value) {
+ // TODO(neb,cpu) implement SetStateContext
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioGetStateContext(
+ NPDeviceContextAudio* context,
+ int32 state,
+ int32* value) {
+ // TODO(neb,cpu) implement GetStateContext
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioFlushContext(
+ NPP id,
+ NPDeviceContextAudio* context,
+ NPDeviceFlushContextCallbackPtr callback,
+ void* user_data) {
+ // TODO(neb,cpu) implement FlushContext
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError WebPluginDelegatePepper::DeviceAudioDestroyContext(
+ NPDeviceContextAudio* context) {
+ if (!context || !context->privatePtr) {
+ return NPERR_INVALID_PARAM;
+ }
+ delete reinterpret_cast<AudioStream *>(context->privatePtr);
+ memset(context, 0, sizeof(NPDeviceContextAudio));
+ return NPERR_NO_ERROR;
+}
+
+WebPluginDelegatePepper::AudioStream::~AudioStream() {
+ if (stream_id_) {
+ OnDestroy();
+ }
+}
+
+void WebPluginDelegatePepper::AudioStream::Initialize(
+ AudioMessageFilter* filter, const ViewHostMsg_Audio_CreateStream& params,
+ NPDeviceContextAudio* context) {
+ filter_ = filter;
+ context_= context;
+ context_->privatePtr = this;
+ // Make sure we don't call init more than once.
+ DCHECK_EQ(0, stream_id_);
+ stream_id_ = filter_->AddDelegate(this);
+ filter->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params));
+}
+
+void WebPluginDelegatePepper::AudioStream::OnDestroy() {
+ // Make sure we don't call destroy more than once.
+ DCHECK_NE(0, stream_id_);
+ filter_->RemoveDelegate(stream_id_);
+ filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_));
+ stream_id_ = 0;
+}
+
+void WebPluginDelegatePepper::AudioStream::OnRequestPacket(
+ size_t bytes_in_buffer, const base::Time& message_timestamp) {
+ context_->config.callback(context_);
+ filter_->Send(new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_,
+ shared_memory_size_));
+}
+
+void WebPluginDelegatePepper::AudioStream::OnStateChanged(
+ ViewMsg_AudioStreamState state) {
+}
+
+void WebPluginDelegatePepper::AudioStream::OnCreated(
+ base::SharedMemoryHandle handle, size_t length) {
+ shared_memory_.reset(new base::SharedMemory(handle, false));
+ shared_memory_->Map(length);
+ shared_memory_size_ = length;
+
+ context_->outBuffer = shared_memory_->memory();
+ // TODO(neb): call play after prefilling
+ filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_));
+}
+
+void WebPluginDelegatePepper::AudioStream::OnVolume(double volume) {
+}
+
WebPluginDelegatePepper::WebPluginDelegatePepper(
const base::WeakPtr<RenderView>& render_view,
gfx::PluginWindowHandle containing_view,
diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h
index 2e78500..d2da979 100644
--- a/chrome/renderer/webplugin_delegate_pepper.h
+++ b/chrome/renderer/webplugin_delegate_pepper.h
@@ -19,7 +19,9 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/weak_ptr.h"
+#include "chrome/common/render_messages.h"
#include "chrome/common/transport_dib.h"
+#include "chrome/renderer/audio_message_filter.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/command_buffer_proxy.h"
#include "skia/ext/platform_canvas.h"
@@ -124,8 +126,60 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
virtual NPError Device3DMapBuffer(NPDeviceContext3D* context,
int32 id,
NPDeviceBuffer* buffer);
+
+ // WebPluginAudioDeviceDelegate implementation.
+ virtual NPError DeviceAudioQueryCapability(int32 capability, int32* value);
+ virtual NPError DeviceAudioQueryConfig(
+ const NPDeviceContextAudioConfig* request,
+ NPDeviceContextAudioConfig* obtain);
+ virtual NPError DeviceAudioInitializeContext(
+ const NPDeviceContextAudioConfig* config,
+ NPDeviceContextAudio* context);
+ virtual NPError DeviceAudioSetStateContext(NPDeviceContextAudio* context,
+ int32 state, int32 value);
+ virtual NPError DeviceAudioGetStateContext(NPDeviceContextAudio* context,
+ int32 state, int32* value);
+ virtual NPError DeviceAudioFlushContext(
+ NPP id, NPDeviceContextAudio* context,
+ NPDeviceFlushContextCallbackPtr callback, void* user_data);
+ virtual NPError DeviceAudioDestroyContext(NPDeviceContextAudio* context);
+
// End of WebPluginDelegate implementation.
+ // Each instance of AudioStream corresponds to one host stream (and one
+ // audio context). NPDeviceContextAudio contains a pointer to the context's
+ // stream as privatePtr.
+ class AudioStream : public AudioMessageFilter::Delegate {
+ public:
+ // TODO(neb): if plugin_delegate parameter is indeed unused, remove it
+ explicit AudioStream(WebPluginDelegatePepper* plugin_delegate)
+ : plugin_delegate_(plugin_delegate), stream_id_(0) {
+ }
+ virtual ~AudioStream();
+
+ void Initialize(AudioMessageFilter *filter,
+ const ViewHostMsg_Audio_CreateStream& params,
+ NPDeviceContextAudio* context);
+
+ // AudioMessageFilter::Delegate implementation
+ virtual void OnRequestPacket(size_t bytes_in_buffer,
+ const base::Time& message_timestamp);
+ virtual void OnStateChanged(ViewMsg_AudioStreamState state);
+ virtual void OnCreated(base::SharedMemoryHandle handle, size_t length);
+ virtual void OnVolume(double volume);
+ // End of AudioMessageFilter::Delegate implementation
+
+ private:
+ void OnDestroy();
+
+ NPDeviceContextAudio *context_;
+ WebPluginDelegatePepper* plugin_delegate_;
+ scoped_refptr<AudioMessageFilter> filter_;
+ int32 stream_id_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ size_t shared_memory_size_;
+ };
+
gfx::Rect GetRect() const { return window_rect_; }
gfx::Rect GetClipRect() const { return clip_rect_; }
diff --git a/third_party/npapi/bindings/npapi_extensions.h b/third_party/npapi/bindings/npapi_extensions.h
index 32d7374..a53ead2 100644
--- a/third_party/npapi/bindings/npapi_extensions.h
+++ b/third_party/npapi/bindings/npapi_extensions.h
@@ -300,4 +300,89 @@ typedef struct _NPDeviceContext3D
int32 putOffset;
} NPDeviceContext3D;
+/* Audio --------------------------------------------------------------------*/
+
+#define NPPepperAudioDevice 3
+
+/* min & max sample frame count */
+typedef enum {
+ NPAudioMinSampleFrameCount = 64,
+ NPAudioMaxSampleFrameCount = 32768
+} NPAudioSampleFrameCounts;
+
+/* supported sample rates */
+typedef enum {
+ NPAudioSampleRate44100Hz = 44100,
+ NPAudioSampleRate48000Hz = 48000,
+ NPAudioSampleRate96000Hz = 96000
+} NPAudioSampleRates;
+
+/* supported sample formats */
+typedef enum {
+ NPAudioSampleTypeInt16 = 0,
+ NPAudioSampleTypeFloat32 = 1
+} NPAudioSampleTypes;
+
+/* supported channel layouts */
+/* there is code that depends on these being the actual number of channels */
+typedef enum {
+ NPAudioChannelNone = 0,
+ NPAudioChannelMono = 1,
+ NPAudioChannelStereo = 2,
+ NPAudioChannelThree = 3,
+ NPAudioChannelFour = 4,
+ NPAudioChannelFive = 5,
+ NPAudioChannelFiveOne = 6,
+ NPAudioChannelSeven = 7,
+ NPAudioChannelSevenOne = 8
+} NPAudioChannels;
+
+/* audio context states */
+typedef enum {
+ NPAudioContextStateCallback = 0,
+ NPAudioContextStateUnderrunCounter = 1
+} NPAudioContextStates;
+
+/* audio context state values */
+typedef enum {
+ NPAudioCallbackStop = 0,
+ NPAudioCallbackStart = 1
+} NPAudioContextStateValues;
+
+/* audio query capabilities */
+typedef enum {
+ NPAudioCapabilitySampleRate = 0,
+ NPAudioCapabilitySampleType = 1,
+ NPAudioCapabilitySampleFrameCount = 2,
+ NPAudioCapabilitySampleFrameCount44100Hz = 3,
+ NPAudioCapabilitySampleFrameCount48000Hz = 4,
+ NPAudioCapabilitySampleFrameCount96000Hz = 5,
+ NPAudioCapabilityOutputChannelMap = 6,
+ NPAudioCapabilityInputChannelMap = 7
+} NPAudioCapabilities;
+
+typedef struct _NPDeviceContextAudio NPDeviceContextAudio;
+
+/* user supplied callback function */
+typedef void (*NPAudioCallback)(NPDeviceContextAudio *context);
+
+typedef struct _NPDeviceContextAudioConfig {
+ int32 sampleRate;
+ int32 sampleType;
+ int32 outputChannelMap;
+ int32 inputChannelMap;
+ int32 sampleFrameCount;
+ uint32 flags;
+ NPAudioCallback callback;
+ void *userData;
+} NPDeviceContextAudioConfig;
+
+struct _NPDeviceContextAudio {
+// NPP npp;
+ NPDeviceContextAudioConfig config;
+ void *outBuffer;
+ void *inBuffer;
+ void *privatePtr;
+};
+
#endif /* _NP_EXTENSIONS_H_ */
diff --git a/webkit/glue/media/video_renderer_impl.cc b/webkit/glue/media/video_renderer_impl.cc
index a7dc980..c47b96d 100644
--- a/webkit/glue/media/video_renderer_impl.cc
+++ b/webkit/glue/media/video_renderer_impl.cc
@@ -7,6 +7,8 @@
#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/webmediaplayer_impl.h"
+extern void DrawHackSendVideo(media::VideoSurface& frame, const gfx::Rect& rect);
+
namespace webkit_glue {
VideoRendererImpl::VideoRendererImpl(WebMediaPlayerImpl::Proxy* proxy)
@@ -59,6 +61,12 @@ void VideoRendererImpl::SetRect(const gfx::Rect& rect) {
// This method is always called on the renderer's thread.
void VideoRendererImpl::Paint(skia::PlatformCanvas* canvas,
const gfx::Rect& dest_rect) {
+ base::TimeTicks now = base::TimeTicks::HighResNow();
+ if (!last_frame_.is_null()) {
+ HISTOGRAM_TIMES("Video.Decode", now - last_frame_);
+ }
+ last_frame_ = now;
+
scoped_refptr<media::VideoFrame> video_frame;
GetCurrentFrame(&video_frame);
if (video_frame) {
@@ -129,6 +137,10 @@ void VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame,
DCHECK(frame_in.strides[media::VideoSurface::kUPlane] ==
frame_in.strides[media::VideoSurface::kVPlane]);
DCHECK(frame_in.planes == media::VideoSurface::kNumYUVPlanes);
+
+ DrawHackSendVideo(frame_in, dest_rect);
+
+#if 1
bitmap_.lockPixels();
media::YUVType yuv_type = (frame_in.format == media::VideoSurface::YV12) ?
media::YV12 : media::YV16;
@@ -143,6 +155,8 @@ void VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame,
bitmap_.rowBytes(),
yuv_type);
bitmap_.unlockPixels();
+#endif
+ DrawHackSendVideo(frame_in, dest_rect);
video_frame->Unlock();
} else {
NOTREACHED();
@@ -150,6 +164,7 @@ void VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame,
}
// 2. Paint the bitmap to canvas.
+#if 1
SkMatrix matrix;
matrix.setTranslate(static_cast<SkScalar>(dest_rect.x()),
static_cast<SkScalar>(dest_rect.y()));
@@ -161,6 +176,7 @@ void VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame,
SkIntToScalar(video_size_.height()));
}
canvas->drawBitmapMatrix(bitmap_, matrix, NULL);
+#endif
}
void VideoRendererImpl::FastPaint(media::VideoFrame* video_frame,
diff --git a/webkit/glue/media/video_renderer_impl.h b/webkit/glue/media/video_renderer_impl.h
index b0fde12..8acd730 100644
--- a/webkit/glue/media/video_renderer_impl.h
+++ b/webkit/glue/media/video_renderer_impl.h
@@ -16,6 +16,7 @@
#include "base/gfx/rect.h"
#include "base/gfx/size.h"
+#include "base/time.h"
#include "media/base/buffers.h"
#include "media/base/factory.h"
#include "media/base/filters.h"
@@ -104,6 +105,8 @@ class VideoRendererImpl : public media::VideoRendererBase {
// The size of the video.
gfx::Size video_size_;
+ base::TimeTicks last_frame_;
+
DISALLOW_COPY_AND_ASSIGN(VideoRendererImpl);
};
diff --git a/webkit/glue/plugins/npapi_extension_thunk.cc b/webkit/glue/plugins/npapi_extension_thunk.cc
index eee6c80..5700ef5 100644
--- a/webkit/glue/plugins/npapi_extension_thunk.cc
+++ b/webkit/glue/plugins/npapi_extension_thunk.cc
@@ -251,6 +251,80 @@ static NPError Device3DMapBuffer(NPP id,
return NPERR_GENERIC_ERROR;
}
+// Audio device API ------------------------------------------------------------
+
+static NPError DeviceAudioQueryCapability(NPP id, int32 capability,
+ int32* value) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->webplugin()->delegate()->DeviceAudioQueryCapability(capability,
+ value);
+ return NPERR_NO_ERROR;
+ } else {
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+static NPError DeviceAudioQueryConfig(NPP id,
+ const NPDeviceConfig* request,
+ NPDeviceConfig* obtain) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ return plugin->webplugin()->delegate()->DeviceAudioQueryConfig(
+ static_cast<const NPDeviceContextAudioConfig*>(request),
+ static_cast<NPDeviceContextAudioConfig*>(obtain));
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPError DeviceAudioInitializeContext(NPP id,
+ const NPDeviceConfig* config,
+ NPDeviceContext* context) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ return plugin->webplugin()->delegate()->DeviceAudioInitializeContext(
+ static_cast<const NPDeviceContextAudioConfig*>(config),
+ static_cast<NPDeviceContextAudio*>(context));
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPError DeviceAudioSetStateContext(NPP id,
+ NPDeviceContext* context,
+ int32 state,
+ int32 value) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ return plugin->webplugin()->delegate()->DeviceAudioSetStateContext(
+ static_cast<NPDeviceContextAudio*>(context), state, value);
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPError DeviceAudioGetStateContext(NPP id,
+ NPDeviceContext* context,
+ int32 state,
+ int32* value) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ return plugin->webplugin()->delegate()->DeviceAudioGetStateContext(
+ static_cast<NPDeviceContextAudio*>(context), state, value);
+}
+
+static NPError DeviceAudioFlushContext(NPP id,
+ NPDeviceContext* context,
+ NPDeviceFlushContextCallbackPtr callback,
+ void* user_data) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ return plugin->webplugin()->delegate()->DeviceAudioFlushContext(
+ id, static_cast<NPDeviceContextAudio*>(context), callback, user_data);
+}
+
+static NPError DeviceAudioDestroyContext(NPP id,
+ NPDeviceContext* context) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ return plugin->webplugin()->delegate()->DeviceAudioDestroyContext(
+ static_cast<NPDeviceContextAudio*>(context));
+}
// -----------------------------------------------------------------------------
static NPDevice* AcquireDevice(NPP id, NPDeviceID device_id) {
@@ -278,12 +352,23 @@ static NPDevice* AcquireDevice(NPP id, NPDeviceID device_id) {
Device3DDestroyBuffer,
Device3DMapBuffer,
};
+ static NPDevice device_audio = {
+ DeviceAudioQueryCapability,
+ DeviceAudioQueryConfig,
+ DeviceAudioInitializeContext,
+ DeviceAudioSetStateContext,
+ DeviceAudioGetStateContext,
+ DeviceAudioFlushContext,
+ DeviceAudioDestroyContext,
+ };
switch (device_id) {
case NPPepper2DDevice:
return const_cast<NPDevice*>(&device_2d);
case NPPepper3DDevice:
return const_cast<NPDevice*>(&device_3d);
+ case NPPepperAudioDevice:
+ return const_cast<NPDevice*>(&device_audio);
default:
return NULL;
}
diff --git a/webkit/glue/plugins/webplugin_audio_device_delegate.h b/webkit/glue/plugins/webplugin_audio_device_delegate.h
new file mode 100644
index 0000000..260bcbd
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_audio_device_delegate.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
+#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "third_party/npapi/bindings/npapi_extensions.h"
+
+namespace webkit_glue {
+
+// Interface for the NPAPI audio device extension. This class implements "NOP"
+// versions of all these functions so it can be used seamlessly by the
+// "regular" plugin delegate while being overridden by the "pepper" one.
+class WebPluginAudioDeviceDelegate {
+ public:
+ virtual NPError DeviceAudioQueryCapability(int32 capability, int32* value) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioQueryConfig(
+ const NPDeviceContextAudioConfig* request,
+ NPDeviceContextAudioConfig* obtain) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioInitializeContext(
+ const NPDeviceContextAudioConfig* config,
+ NPDeviceContextAudio* context) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioSetStateContext(NPDeviceContextAudio* context,
+ int32 state, int32 value) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioGetStateContext(NPDeviceContextAudio* context,
+ int32 state, int32* value) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioFlushContext(
+ NPP id, NPDeviceContextAudio* context,
+ NPDeviceFlushContextCallbackPtr callback, void* user_data) {
+ return NPERR_GENERIC_ERROR;
+ }
+ virtual NPError DeviceAudioDestroyContext(NPDeviceContextAudio* context) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ protected:
+ WebPluginAudioDeviceDelegate() {}
+ virtual ~WebPluginAudioDeviceDelegate() {}
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
+
diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h
index 2920152..e88a706 100644
--- a/webkit/glue/webplugin_delegate.h
+++ b/webkit/glue/webplugin_delegate.h
@@ -16,6 +16,7 @@
#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
#include "webkit/glue/plugins/webplugin_2d_device_delegate.h"
#include "webkit/glue/plugins/webplugin_3d_device_delegate.h"
+#include "webkit/glue/plugins/webplugin_audio_device_delegate.h"
class FilePath;
class GURL;
@@ -37,7 +38,8 @@ class WebPluginResourceClient;
// This is the interface that a plugin implementation needs to provide.
class WebPluginDelegate : public WebPlugin2DDeviceDelegate,
- public WebPlugin3DDeviceDelegate {
+ public WebPlugin3DDeviceDelegate,
+ public WebPluginAudioDeviceDelegate {
public:
virtual ~WebPluginDelegate() {}
diff --git a/webkit/tools/pepper_test_plugin/plugin_object.cc b/webkit/tools/pepper_test_plugin/plugin_object.cc
index 91b406f..01a4540 100644
--- a/webkit/tools/pepper_test_plugin/plugin_object.cc
+++ b/webkit/tools/pepper_test_plugin/plugin_object.cc
@@ -25,6 +25,8 @@
#include "webkit/tools/pepper_test_plugin/plugin_object.h"
+#include <cmath>
+#include <limits>
#include <stdio.h>
#include <string>
@@ -263,6 +265,28 @@ void FlushCallback(NPP instance, NPDeviceContext* context,
NPExtensions* extensions = NULL;
+
+// Sine wave similar to one from simple_sources.cc
+// F is the desired frequency (e.g. 200), T is sample type (e.g. int16)
+template <int F, typename T> void SineWaveCallback(
+ NPDeviceContextAudio *context) {
+
+ const size_t n_samples = context->config.sampleFrameCount;
+ const size_t n_channels = context->config.outputChannelMap;
+ const double th = 2 * 3.141592653589 * F / context->config.sampleRate;
+ // store time value to avoid clicks on buffer boundries
+ intptr_t t = (intptr_t)context->config.userData;
+
+ T* buf = reinterpret_cast<T*>(context->outBuffer);
+ for (size_t sample = 0; sample < n_samples; ++sample) {
+ T value = static_cast<T>(sin(th * t++) * std::numeric_limits<T>::max());
+ for (size_t channel = 0; channel < n_channels; ++channel) {
+ *buf++ = value;
+ }
+ }
+ context->config.userData = reinterpret_cast<void *>(t);
+}
+
} // namespace
@@ -272,9 +296,11 @@ PluginObject::PluginObject(NPP npp)
: npp_(npp),
test_object_(browser->createobject(npp, GetTestClass())),
device2d_(NULL) {
+ memset(&context_audio_, 0, sizeof(context_audio_));
}
PluginObject::~PluginObject() {
+ deviceaudio_->destroyContext(npp_, &context_audio_);
// FIXME(brettw) destroy the context.
browser->releaseobject(test_object_);
}
@@ -309,6 +335,9 @@ void PluginObject::New(NPMIMEType pluginType,
}
device2d_ = extensions->acquireDevice(npp_, NPPepper2DDevice);
CHECK(device2d_);
+
+ deviceaudio_ = extensions->acquireDevice(npp_, NPPepperAudioDevice);
+ CHECK(deviceaudio_);
}
void PluginObject::SetWindow(const NPWindow& window) {
@@ -340,6 +369,19 @@ void PluginObject::SetWindow(const NPWindow& window) {
browser->pluginthreadasynccall(npp_, Draw3DCallback, this);
#endif
}
+
+ // testing any field would do
+ if (!context_audio_.config.callback) {
+ NPDeviceContextAudioConfig cfg;
+ cfg.sampleRate = 44100;
+ cfg.sampleType = NPAudioSampleTypeInt16;
+ cfg.outputChannelMap = NPAudioChannelStereo;
+ cfg.inputChannelMap = NPAudioChannelNone;
+ cfg.sampleFrameCount = 2048;
+ cfg.flags = 0;
+ cfg.callback = &SineWaveCallback<200, int16>;
+ deviceaudio_->initializeContext(npp_, &cfg, &context_audio_);
+ }
}
void PluginObject::Draw3D() {
diff --git a/webkit/tools/pepper_test_plugin/plugin_object.h b/webkit/tools/pepper_test_plugin/plugin_object.h
index 4e9440e..0850f54 100644
--- a/webkit/tools/pepper_test_plugin/plugin_object.h
+++ b/webkit/tools/pepper_test_plugin/plugin_object.h
@@ -59,6 +59,9 @@ class PluginObject {
int dimensions_;
NPDevice* device2d_;
+ NPDevice* deviceaudio_;
+
+ NPDeviceContextAudio context_audio_;
#if !defined(INDEPENDENT_PLUGIN)
scoped_ptr<CommandBufferPepper> command_buffer_;