diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 21:30:25 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 21:30:25 +0000 |
commit | 321ad87b01c1e040f3f121044f8c255ca5548b30 (patch) | |
tree | 50a7575b7ee9d0ec0498395a6557af7b74e6ecfd | |
parent | db2ff4b4607eb2a54b30ea9c4b8248e7a1cebfe5 (diff) | |
download | chromium_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.cc | 142 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_pepper.h | 54 | ||||
-rw-r--r-- | third_party/npapi/bindings/npapi_extensions.h | 85 | ||||
-rw-r--r-- | webkit/glue/media/video_renderer_impl.cc | 16 | ||||
-rw-r--r-- | webkit/glue/media/video_renderer_impl.h | 3 | ||||
-rw-r--r-- | webkit/glue/plugins/npapi_extension_thunk.cc | 85 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_audio_device_delegate.h | 56 | ||||
-rw-r--r-- | webkit/glue/webplugin_delegate.h | 4 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/plugin_object.cc | 42 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/plugin_object.h | 3 |
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_; |