Commit 5e19b8ba authored by thembrown@gmail.com's avatar thembrown@gmail.com

Support configuring number of audio buffers in MediaStream Pepper API.

A optionally larger number of buffers makes recording audio in a pnacl module
more reliable when latency is not an issue.

BUG=330851

Review URL: https://codereview.chromium.org/290993005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274511 0039d316-1c4b-4281-b951-d872f2087c98
parent b4b8711a
...@@ -223,6 +223,7 @@ Luke Zarko <lukezarko@gmail.com> ...@@ -223,6 +223,7 @@ Luke Zarko <lukezarko@gmail.com>
Maarten Lankhorst <m.b.lankhorst@gmail.com> Maarten Lankhorst <m.b.lankhorst@gmail.com>
Magnus Danielsson <fuzzac@gmail.com> Magnus Danielsson <fuzzac@gmail.com>
Mahesh Kulkarni <mahesh.kk@samsung.com> Mahesh Kulkarni <mahesh.kk@samsung.com>
Manuel Braun <thembrown@gmail.com>
Mao Yujie <maojie0924@gmail.com> Mao Yujie <maojie0924@gmail.com>
Mao Yujie <yujie.mao@intel.com> Mao Yujie <yujie.mao@intel.com>
Marco Rodrigues <gothicx@gmail.com> Marco Rodrigues <gothicx@gmail.com>
......
...@@ -4,24 +4,33 @@ ...@@ -4,24 +4,33 @@
#include "content/renderer/pepper/pepper_media_stream_audio_track_host.h" #include "content/renderer/pepper/pepper_media_stream_audio_track_host.h"
#include <algorithm>
#include "base/bind.h" #include "base/bind.h"
#include "base/location.h" #include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/message_loop/message_loop_proxy.h" #include "base/message_loop/message_loop_proxy.h"
#include "base/numerics/safe_math.h"
#include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppb_audio_buffer.h" #include "ppapi/c/ppb_audio_buffer.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
#include "ppapi/shared_impl/media_stream_buffer.h" #include "ppapi/shared_impl/media_stream_buffer.h"
using media::AudioParameters; using media::AudioParameters;
using ppapi::host::HostMessageContext;
using ppapi::MediaStreamAudioTrackShared;
namespace { namespace {
// Max audio buffer duration in milliseconds. // Max audio buffer duration in milliseconds.
const uint32_t kMaxDuration = 10; const uint32_t kMaxDuration = 10;
// TODO(penghuang): make this configurable. const int32_t kDefaultNumberOfBuffers = 4;
const int32_t kNumberOfBuffers = 4; const int32_t kMaxNumberOfBuffers = 1000; // 10 sec
// Returns true if the |sample_rate| is supported in // Returns true if the |sample_rate| is supported in
// |PP_AudioBuffer_SampleRate|, otherwise false. // |PP_AudioBuffer_SampleRate|, otherwise false.
...@@ -57,7 +66,9 @@ PepperMediaStreamAudioTrackHost::AudioSink::AudioSink( ...@@ -57,7 +66,9 @@ PepperMediaStreamAudioTrackHost::AudioSink::AudioSink(
: host_(host), : host_(host),
buffer_data_size_(0), buffer_data_size_(0),
main_message_loop_proxy_(base::MessageLoopProxy::current()), main_message_loop_proxy_(base::MessageLoopProxy::current()),
weak_factory_(this) {} weak_factory_(this),
number_of_buffers_(kDefaultNumberOfBuffers),
bytes_per_second_(0) {}
PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() { PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() {
DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
...@@ -71,15 +82,41 @@ void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) { ...@@ -71,15 +82,41 @@ void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) {
buffers_.push_back(index); buffers_.push_back(index);
} }
void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffersOnMainThread( void PepperMediaStreamAudioTrackHost::AudioSink::Configure(
int32_t number_of_buffers, int32_t number_of_buffers) {
int32_t buffer_size) { DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
bool changed = false;
if (number_of_buffers != number_of_buffers_)
changed = true;
number_of_buffers_ = number_of_buffers;
// Initialize later in OnSetFormat if bytes_per_second_ is not know yet.
if (changed && bytes_per_second_ > 0)
InitBuffers();
}
void PepperMediaStreamAudioTrackHost::AudioSink::SetFormatOnMainThread(
int bytes_per_second) {
bytes_per_second_ = bytes_per_second;
InitBuffers();
}
void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffers() {
DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
bool result = host_->InitBuffers(number_of_buffers, buffer_size, kRead); // The size is slightly bigger than necessary, because 8 extra bytes are
// added into the struct. Also see |MediaStreamBuffer|.
base::CheckedNumeric<int32_t> buffer_size = bytes_per_second_;
buffer_size *= kMaxDuration;
buffer_size /= base::Time::kMillisecondsPerSecond;
buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio);
bool result = host_->InitBuffers(number_of_buffers_,
buffer_size.ValueOrDie(),
kRead);
// TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin. // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin.
CHECK(result); CHECK(result);
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
for (int32_t i = 0; i < number_of_buffers; ++i) { buffers_.clear();
for (int32_t i = 0; i < number_of_buffers_; ++i) {
int32_t index = host_->buffer_manager()->DequeueBuffer(); int32_t index = host_->buffer_manager()->DequeueBuffer();
DCHECK_GE(index, 0); DCHECK_GE(index, 0);
buffers_.push_back(index); buffers_.push_back(index);
...@@ -154,18 +191,12 @@ void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat( ...@@ -154,18 +191,12 @@ void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat(
} else { } else {
audio_thread_checker_.DetachFromThread(); audio_thread_checker_.DetachFromThread();
original_audio_params_ = params; original_audio_params_ = params;
// The size is slightly bigger than necessary, because 8 extra bytes are
// added into the struct. Also see |MediaStreamBuffer|.
size_t max_data_size = params.sample_rate() * params.bits_per_sample() / 8 *
params.channels() * kMaxDuration / 1000;
size_t size = sizeof(ppapi::MediaStreamBuffer::Audio) + max_data_size;
main_message_loop_proxy_->PostTask( main_message_loop_proxy_->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&AudioSink::InitBuffersOnMainThread, base::Bind(&AudioSink::SetFormatOnMainThread,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
kNumberOfBuffers, params.GetBytesPerSecond()));
static_cast<int32_t>(size)));
} }
} }
...@@ -185,6 +216,32 @@ PepperMediaStreamAudioTrackHost::~PepperMediaStreamAudioTrackHost() { ...@@ -185,6 +216,32 @@ PepperMediaStreamAudioTrackHost::~PepperMediaStreamAudioTrackHost() {
OnClose(); OnClose();
} }
int32_t PepperMediaStreamAudioTrackHost::OnResourceMessageReceived(
const IPC::Message& msg,
HostMessageContext* context) {
PPAPI_BEGIN_MESSAGE_MAP(PepperMediaStreamAudioTrackHost, msg)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_MediaStreamAudioTrack_Configure, OnHostMsgConfigure)
PPAPI_END_MESSAGE_MAP()
return PepperMediaStreamTrackHostBase::OnResourceMessageReceived(msg,
context);
}
int32_t PepperMediaStreamAudioTrackHost::OnHostMsgConfigure(
HostMessageContext* context,
const MediaStreamAudioTrackShared::Attributes& attributes) {
if (!MediaStreamAudioTrackShared::VerifyAttributes(attributes))
return PP_ERROR_BADARGUMENT;
int32_t buffers = attributes.buffers
? std::min(kMaxNumberOfBuffers, attributes.buffers)
: kDefaultNumberOfBuffers;
audio_sink_.Configure(buffers);
context->reply_msg = PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply();
return PP_OK;
}
void PepperMediaStreamAudioTrackHost::OnClose() { void PepperMediaStreamAudioTrackHost::OnClose() {
if (connected_) { if (connected_) {
MediaStreamAudioSink::RemoveFromAudioTrack(&audio_sink_, track_); MediaStreamAudioSink::RemoveFromAudioTrack(&audio_sink_, track_);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "content/public/renderer/media_stream_audio_sink.h" #include "content/public/renderer/media_stream_audio_sink.h"
#include "content/renderer/pepper/pepper_media_stream_track_host_base.h" #include "content/renderer/pepper/pepper_media_stream_track_host_base.h"
#include "media/audio/audio_parameters.h" #include "media/audio/audio_parameters.h"
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
namespace base { namespace base {
...@@ -43,10 +44,14 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase { ...@@ -43,10 +44,14 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
// This function is called on the main thread. // This function is called on the main thread.
void EnqueueBuffer(int32_t index); void EnqueueBuffer(int32_t index);
// This function is called on the main thread.
void Configure(int32_t number_of_buffers);
private: private:
// Initializes buffers on the main thread. // Initializes buffers on the main thread.
void InitBuffersOnMainThread(int32_t number_of_buffers, void SetFormatOnMainThread(int bytes_per_second);
int32_t buffer_size);
void InitBuffers();
// Send enqueue buffer message on the main thread. // Send enqueue buffer message on the main thread.
void SendEnqueueBufferMessageOnMainThread(int32_t index); void SendEnqueueBufferMessageOnMainThread(int32_t index);
...@@ -99,11 +104,27 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase { ...@@ -99,11 +104,27 @@ class PepperMediaStreamAudioTrackHost : public PepperMediaStreamTrackHostBase {
base::WeakPtrFactory<AudioSink> weak_factory_; base::WeakPtrFactory<AudioSink> weak_factory_;
// Number of buffers.
int32_t number_of_buffers_;
// Number of bytes per second.
int bytes_per_second_;
DISALLOW_COPY_AND_ASSIGN(AudioSink); DISALLOW_COPY_AND_ASSIGN(AudioSink);
}; };
virtual ~PepperMediaStreamAudioTrackHost(); virtual ~PepperMediaStreamAudioTrackHost();
// ResourceMessageHandler overrides:
virtual int32_t OnResourceMessageReceived(
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) OVERRIDE;
// Message handlers:
int32_t OnHostMsgConfigure(
ppapi::host::HostMessageContext* context,
const ppapi::MediaStreamAudioTrackShared::Attributes& attributes);
// PepperMediaStreamTrackHostBase overrides: // PepperMediaStreamTrackHostBase overrides:
virtual void OnClose() OVERRIDE; virtual void OnClose() OVERRIDE;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "content/renderer/pepper/pepper_media_stream_track_host_base.h" #include "content/renderer/pepper/pepper_media_stream_track_host_base.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_thread.h"
#include "content/public/renderer/renderer_ppapi_host.h" #include "content/public/renderer/renderer_ppapi_host.h"
#include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_errors.h"
...@@ -36,20 +37,26 @@ bool PepperMediaStreamTrackHostBase::InitBuffers(int32_t number_of_buffers, ...@@ -36,20 +37,26 @@ bool PepperMediaStreamTrackHostBase::InitBuffers(int32_t number_of_buffers,
DCHECK_GT(buffer_size, DCHECK_GT(buffer_size,
static_cast<int32_t>(sizeof(ppapi::MediaStreamBuffer::Header))); static_cast<int32_t>(sizeof(ppapi::MediaStreamBuffer::Header)));
// Make each buffer 4 byte aligned. // Make each buffer 4 byte aligned.
buffer_size = (buffer_size + 3) & ~0x3; base::CheckedNumeric<int32_t> buffer_size_aligned = buffer_size;
buffer_size_aligned += (4 - buffer_size % 4);
// TODO(penghuang): |HostAllocateSharedMemoryBuffer| uses sync IPC. We should // TODO(penghuang): |HostAllocateSharedMemoryBuffer| uses sync IPC. We should
// avoid it. // avoid it.
int32_t size = number_of_buffers * buffer_size; base::CheckedNumeric<int32_t> size = number_of_buffers * buffer_size_aligned;
if (!size.IsValid())
return false;
content::RenderThread* render_thread = content::RenderThread::Get(); content::RenderThread* render_thread = content::RenderThread::Get();
scoped_ptr<base::SharedMemory> shm( scoped_ptr<base::SharedMemory> shm(
render_thread->HostAllocateSharedMemoryBuffer(size).Pass()); render_thread->HostAllocateSharedMemoryBuffer(size.ValueOrDie()).Pass());
if (!shm) if (!shm)
return false; return false;
base::SharedMemoryHandle shm_handle = shm->handle(); base::SharedMemoryHandle shm_handle = shm->handle();
if (!buffer_manager_.SetBuffers( if (!buffer_manager_.SetBuffers(number_of_buffers,
number_of_buffers, buffer_size, shm.Pass(), true)) { buffer_size_aligned.ValueOrDie(),
shm.Pass(),
true)) {
return false; return false;
} }
...@@ -62,13 +69,14 @@ bool PepperMediaStreamTrackHostBase::InitBuffers(int32_t number_of_buffers, ...@@ -62,13 +69,14 @@ bool PepperMediaStreamTrackHostBase::InitBuffers(int32_t number_of_buffers,
#error Not implemented. #error Not implemented.
#endif #endif
SerializedHandle handle(host_->ShareHandleWithRemote(platform_file, false), SerializedHandle handle(host_->ShareHandleWithRemote(platform_file, false),
size); size.ValueOrDie());
bool readonly = (track_type == kRead); bool readonly = (track_type == kRead);
host()->SendUnsolicitedReplyWithHandles( host()->SendUnsolicitedReplyWithHandles(
pp_resource(), pp_resource(),
PpapiPluginMsg_MediaStreamTrack_InitBuffers(number_of_buffers, PpapiPluginMsg_MediaStreamTrack_InitBuffers(
buffer_size, number_of_buffers,
readonly), buffer_size_aligned.ValueOrDie(),
readonly),
std::vector<SerializedHandle>(1, handle)); std::vector<SerializedHandle>(1, handle));
return true; return true;
} }
......
...@@ -83,7 +83,8 @@ interface PPB_MediaStreamAudioTrack { ...@@ -83,7 +83,8 @@ interface PPB_MediaStreamAudioTrack {
* the input buffers. If all buffers are filled, then samples will be * the input buffers. If all buffers are filled, then samples will be
* dropped. The application can detect this by examining the timestamp on * dropped. The application can detect this by examining the timestamp on
* returned buffers. If <code>Configure()</code> is not called, default * returned buffers. If <code>Configure()</code> is not called, default
* settings will be used. * settings will be used. Calls to Configure while the plugin holds
* buffers will fail.
* Example usage from plugin code: * Example usage from plugin code:
* @code * @code
* int32_t attribs[] = { * int32_t attribs[] = {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
/* From ppb_media_stream_audio_track.idl modified Fri Mar 28 10:13:34 2014. */ /* From ppb_media_stream_audio_track.idl modified Wed May 28 09:36:15 2014. */
#ifndef PPAPI_C_PPB_MEDIA_STREAM_AUDIO_TRACK_H_ #ifndef PPAPI_C_PPB_MEDIA_STREAM_AUDIO_TRACK_H_
#define PPAPI_C_PPB_MEDIA_STREAM_AUDIO_TRACK_H_ #define PPAPI_C_PPB_MEDIA_STREAM_AUDIO_TRACK_H_
...@@ -98,7 +98,8 @@ struct PPB_MediaStreamAudioTrack_0_1 { ...@@ -98,7 +98,8 @@ struct PPB_MediaStreamAudioTrack_0_1 {
* the input buffers. If all buffers are filled, then samples will be * the input buffers. If all buffers are filled, then samples will be
* dropped. The application can detect this by examining the timestamp on * dropped. The application can detect this by examining the timestamp on
* returned buffers. If <code>Configure()</code> is not called, default * returned buffers. If <code>Configure()</code> is not called, default
* settings will be used. * settings will be used. Calls to Configure while the plugin holds
* buffers will fail.
* Example usage from plugin code: * Example usage from plugin code:
* @code * @code
* int32_t attribs[] = { * int32_t attribs[] = {
......
...@@ -56,7 +56,8 @@ class MediaStreamAudioTrack : public Resource { ...@@ -56,7 +56,8 @@ class MediaStreamAudioTrack : public Resource {
/// all input buffers. If all buffers are filled, then samples will be /// all input buffers. If all buffers are filled, then samples will be
/// dropped. The application can detect this by examining the timestamp on /// dropped. The application can detect this by examining the timestamp on
/// returned buffers. If <code>Configure()</code> is not called, default /// returned buffers. If <code>Configure()</code> is not called, default
/// settings will be used. /// settings will be used. Calls to Configure while the plugin holds
/// buffers will fail.
/// Example usage from plugin code: /// Example usage from plugin code:
/// @code /// @code
/// int32_t attribs[] = { /// int32_t attribs[] = {
......
...@@ -42,8 +42,10 @@ ...@@ -42,8 +42,10 @@
'shared_impl/media_stream_buffer.h', 'shared_impl/media_stream_buffer.h',
'shared_impl/media_stream_buffer_manager.cc', 'shared_impl/media_stream_buffer_manager.cc',
'shared_impl/media_stream_buffer_manager.h', 'shared_impl/media_stream_buffer_manager.h',
'shared_impl/media_stream_video_track_shared.h', 'shared_impl/media_stream_audio_track_shared.cc',
'shared_impl/media_stream_audio_track_shared.h',
'shared_impl/media_stream_video_track_shared.cc', 'shared_impl/media_stream_video_track_shared.cc',
'shared_impl/media_stream_video_track_shared.h',
'shared_impl/platform_file.cc', 'shared_impl/platform_file.cc',
'shared_impl/platform_file.h', 'shared_impl/platform_file.h',
'shared_impl/ppapi_constants.h', 'shared_impl/ppapi_constants.h',
......
...@@ -177,6 +177,7 @@ ...@@ -177,6 +177,7 @@
'proxy/talk_resource_unittest.cc', 'proxy/talk_resource_unittest.cc',
'proxy/video_decoder_resource_unittest.cc', 'proxy/video_decoder_resource_unittest.cc',
'proxy/websocket_resource_unittest.cc', 'proxy/websocket_resource_unittest.cc',
'shared_impl/media_stream_audio_track_shared_unittest.cc',
'shared_impl/media_stream_buffer_manager_unittest.cc', 'shared_impl/media_stream_buffer_manager_unittest.cc',
'shared_impl/media_stream_video_track_shared_unittest.cc', 'shared_impl/media_stream_video_track_shared_unittest.cc',
'shared_impl/proxy_lock_unittest.cc', 'shared_impl/proxy_lock_unittest.cc',
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "ppapi/proxy/media_stream_audio_track_resource.h" #include "ppapi/proxy/media_stream_audio_track_resource.h"
#include "ppapi/proxy/audio_buffer_resource.h" #include "ppapi/proxy/audio_buffer_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
#include "ppapi/shared_impl/media_stream_buffer.h" #include "ppapi/shared_impl/media_stream_buffer.h"
#include "ppapi/shared_impl/var.h" #include "ppapi/shared_impl/var.h"
...@@ -41,8 +43,46 @@ PP_Bool MediaStreamAudioTrackResource::HasEnded() { ...@@ -41,8 +43,46 @@ PP_Bool MediaStreamAudioTrackResource::HasEnded() {
int32_t MediaStreamAudioTrackResource::Configure( int32_t MediaStreamAudioTrackResource::Configure(
const int32_t attrib_list[], const int32_t attrib_list[],
scoped_refptr<TrackedCallback> callback) { scoped_refptr<TrackedCallback> callback) {
// TODO(penghuang): Implement this function. if (has_ended())
return PP_ERROR_NOTSUPPORTED; return PP_ERROR_FAILED;
if (TrackedCallback::IsPending(configure_callback_) ||
TrackedCallback::IsPending(get_buffer_callback_)) {
return PP_ERROR_INPROGRESS;
}
// Do not support configure if audio buffers are held by plugin.
if (!buffers_.empty())
return PP_ERROR_INPROGRESS;
MediaStreamAudioTrackShared::Attributes attributes;
int i = 0;
for (; attrib_list[i] != PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE; i += 2) {
switch (attrib_list[i]) {
case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS:
attributes.buffers = attrib_list[i + 1];
break;
case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_SAMPLE_RATE:
case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_SAMPLE_SIZE:
case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_CHANNELS:
case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION:
return PP_ERROR_NOTSUPPORTED;
default:
return PP_ERROR_BADARGUMENT;
}
}
if (!MediaStreamAudioTrackShared::VerifyAttributes(attributes))
return PP_ERROR_BADARGUMENT;
configure_callback_ = callback;
Call<PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply>(
RENDERER,
PpapiHostMsg_MediaStreamAudioTrack_Configure(attributes),
base::Bind(&MediaStreamAudioTrackResource::OnPluginMsgConfigureReply,
base::Unretained(this)),
callback);
return PP_OK_COMPLETIONPENDING;
} }
int32_t MediaStreamAudioTrackResource::GetAttrib( int32_t MediaStreamAudioTrackResource::GetAttrib(
...@@ -58,7 +98,8 @@ int32_t MediaStreamAudioTrackResource::GetBuffer( ...@@ -58,7 +98,8 @@ int32_t MediaStreamAudioTrackResource::GetBuffer(
if (has_ended()) if (has_ended())
return PP_ERROR_FAILED; return PP_ERROR_FAILED;
if (TrackedCallback::IsPending(get_buffer_callback_)) if (TrackedCallback::IsPending(configure_callback_) ||
TrackedCallback::IsPending(get_buffer_callback_))
return PP_ERROR_INPROGRESS; return PP_ERROR_INPROGRESS;
*buffer = GetAudioBuffer(); *buffer = GetAudioBuffer();
...@@ -144,5 +185,14 @@ void MediaStreamAudioTrackResource::ReleaseBuffers() { ...@@ -144,5 +185,14 @@ void MediaStreamAudioTrackResource::ReleaseBuffers() {
} }
} }
void MediaStreamAudioTrackResource::OnPluginMsgConfigureReply(
const ResourceMessageReplyParams& params) {
if (TrackedCallback::IsPending(configure_callback_)) {
scoped_refptr<TrackedCallback> callback;
callback.swap(configure_callback_);
callback->Run(params.result());
}
}
} // namespace proxy } // namespace proxy
} // namespace ppapi } // namespace ppapi
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define PPAPI_PROXY_MEDIA_STREAM_AUDIO_TRACK_RESOURCE_H_ #define PPAPI_PROXY_MEDIA_STREAM_AUDIO_TRACK_RESOURCE_H_
#include <map> #include <map>
#include <string>
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "ppapi/proxy/media_stream_track_resource_base.h" #include "ppapi/proxy/media_stream_track_resource_base.h"
...@@ -53,12 +54,17 @@ class PPAPI_PROXY_EXPORT MediaStreamAudioTrackResource ...@@ -53,12 +54,17 @@ class PPAPI_PROXY_EXPORT MediaStreamAudioTrackResource
void ReleaseBuffers(); void ReleaseBuffers();
// IPC message handlers.
void OnPluginMsgConfigureReply(const ResourceMessageReplyParams& params);
// Allocated buffer resources by |GetBuffer()|. // Allocated buffer resources by |GetBuffer()|.
typedef std::map<PP_Resource, scoped_refptr<AudioBufferResource> > BufferMap; typedef std::map<PP_Resource, scoped_refptr<AudioBufferResource> > BufferMap;
BufferMap buffers_; BufferMap buffers_;
PP_Resource* get_buffer_output_; PP_Resource* get_buffer_output_;
scoped_refptr<TrackedCallback> configure_callback_;
scoped_refptr<TrackedCallback> get_buffer_callback_; scoped_refptr<TrackedCallback> get_buffer_callback_;
DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioTrackResource); DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioTrackResource);
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#include "ppapi/shared_impl/file_growth.h" #include "ppapi/shared_impl/file_growth.h"
#include "ppapi/shared_impl/file_path.h" #include "ppapi/shared_impl/file_path.h"
#include "ppapi/shared_impl/file_ref_create_info.h" #include "ppapi/shared_impl/file_ref_create_info.h"
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
#include "ppapi/shared_impl/media_stream_video_track_shared.h" #include "ppapi/shared_impl/media_stream_video_track_shared.h"
#include "ppapi/shared_impl/ppapi_nacl_plugin_args.h" #include "ppapi/shared_impl/ppapi_nacl_plugin_args.h"
#include "ppapi/shared_impl/ppapi_preferences.h" #include "ppapi/shared_impl/ppapi_preferences.h"
...@@ -244,6 +245,10 @@ IPC_STRUCT_TRAITS_BEGIN(ppapi::FlashSiteSetting) ...@@ -244,6 +245,10 @@ IPC_STRUCT_TRAITS_BEGIN(ppapi::FlashSiteSetting)
IPC_STRUCT_TRAITS_MEMBER(permission) IPC_STRUCT_TRAITS_MEMBER(permission)
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ppapi::MediaStreamAudioTrackShared::Attributes)
IPC_STRUCT_TRAITS_MEMBER(buffers)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ppapi::MediaStreamVideoTrackShared::Attributes) IPC_STRUCT_TRAITS_BEGIN(ppapi::MediaStreamVideoTrackShared::Attributes)
IPC_STRUCT_TRAITS_MEMBER(buffers) IPC_STRUCT_TRAITS_MEMBER(buffers)
IPC_STRUCT_TRAITS_MEMBER(width) IPC_STRUCT_TRAITS_MEMBER(width)
...@@ -1444,6 +1449,10 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply, ...@@ -1444,6 +1449,10 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply,
// MediaStream ----------------------------------------------------------------- // MediaStream -----------------------------------------------------------------
IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost, IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost,
std::string /* track_id */) std::string /* track_id */)
IPC_MESSAGE_CONTROL1(
PpapiHostMsg_MediaStreamAudioTrack_Configure,
ppapi::MediaStreamAudioTrackShared::Attributes /* attributes */)
IPC_MESSAGE_CONTROL0(PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply)
IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost, IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost,
std::string /* track_id */) std::string /* track_id */)
IPC_MESSAGE_CONTROL0(PpapiHostMsg_MediaStreamVideoTrack_Create) IPC_MESSAGE_CONTROL0(PpapiHostMsg_MediaStreamVideoTrack_Create)
......
// Copyright 2014 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.
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
namespace ppapi {
// static
bool MediaStreamAudioTrackShared::VerifyAttributes(
const Attributes& attributes) {
if (attributes.buffers < 0)
return false;
return true;
}
} // namespace ppapi
// Copyright 2014 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 PPAPI_SHARED_IMPL_MEDIA_STREAM_AUDIO_TRACK_SHARED_H_
#define PPAPI_SHARED_IMPL_MEDIA_STREAM_AUDIO_TRACK_SHARED_H_
#include "ppapi/c/ppb_audio_buffer.h"
#include "ppapi/shared_impl/ppapi_shared_export.h"
namespace ppapi {
class PPAPI_SHARED_EXPORT MediaStreamAudioTrackShared {
public:
struct Attributes {
Attributes() : buffers(0) {}
int32_t buffers;
};
static bool VerifyAttributes(const Attributes& attributes);
};
} // namespace ppapi
#endif // PPAPI_SHARED_IMPL_MEDIA_STREAM_AUDIO_TRACK_SHARED_H_
// Copyright 2014 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.
#include "ppapi/shared_impl/media_stream_audio_track_shared.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ppapi {
TEST(MediaStreamAudioTrackShared, Verify) {
{
MediaStreamAudioTrackShared::Attributes attributes;
EXPECT_TRUE(MediaStreamAudioTrackShared::VerifyAttributes(attributes));
}
// Verify buffers
{
MediaStreamAudioTrackShared::Attributes attributes;
attributes.buffers = 0;
EXPECT_TRUE(MediaStreamAudioTrackShared::VerifyAttributes(attributes));
attributes.buffers = 8;
EXPECT_TRUE(MediaStreamAudioTrackShared::VerifyAttributes(attributes));
attributes.buffers = 1024;
EXPECT_TRUE(MediaStreamAudioTrackShared::VerifyAttributes(attributes));
attributes.buffers = -1;
EXPECT_FALSE(MediaStreamAudioTrackShared::VerifyAttributes(attributes));
}
}
} // namespace ppapi
...@@ -18,6 +18,9 @@ REGISTER_TEST_CASE(MediaStreamAudioTrack); ...@@ -18,6 +18,9 @@ REGISTER_TEST_CASE(MediaStreamAudioTrack);
namespace { namespace {
// Real max defined in
// content/renderer/pepper/pepper_media_stream_audio_track_host.cc.
const int32_t kMaxNumberOfBuffers = 1000;
const int32_t kTimes = 3; const int32_t kTimes = 3;
const char kJSCode[] = const char kJSCode[] =
"function gotStream(stream) {" "function gotStream(stream) {"
...@@ -53,7 +56,7 @@ bool IsSampleRateValid(PP_AudioBuffer_SampleRate sample_rate) { ...@@ -53,7 +56,7 @@ bool IsSampleRateValid(PP_AudioBuffer_SampleRate sample_rate) {
} }
} }
} } // namespace
TestMediaStreamAudioTrack::TestMediaStreamAudioTrack(TestingInstance* instance) TestMediaStreamAudioTrack::TestMediaStreamAudioTrack(TestingInstance* instance)
: TestCase(instance), : TestCase(instance),
...@@ -70,6 +73,7 @@ TestMediaStreamAudioTrack::~TestMediaStreamAudioTrack() { ...@@ -70,6 +73,7 @@ TestMediaStreamAudioTrack::~TestMediaStreamAudioTrack() {
void TestMediaStreamAudioTrack::RunTests(const std::string& filter) { void TestMediaStreamAudioTrack::RunTests(const std::string& filter) {
RUN_TEST(Create, filter); RUN_TEST(Create, filter);
RUN_TEST(GetBuffer, filter); RUN_TEST(GetBuffer, filter);
RUN_TEST(Configure, filter);
} }
void TestMediaStreamAudioTrack::HandleMessage(const pp::Var& message) { void TestMediaStreamAudioTrack::HandleMessage(const pp::Var& message) {
...@@ -140,3 +144,85 @@ std::string TestMediaStreamAudioTrack::TestGetBuffer() { ...@@ -140,3 +144,85 @@ std::string TestMediaStreamAudioTrack::TestGetBuffer() {
audio_track_ = pp::MediaStreamAudioTrack(); audio_track_ = pp::MediaStreamAudioTrack();
PASS(); PASS();
} }
std::string TestMediaStreamAudioTrack::TestConfigure() {
// Create a track.
instance_->EvalScript(kJSCode);
event_.Wait();
event_.Reset();
ASSERT_FALSE(audio_track_.is_null());
ASSERT_FALSE(audio_track_.HasEnded());
ASSERT_FALSE(audio_track_.GetId().empty());
PP_TimeDelta timestamp = 0.0;
// Configure number of buffers.
struct {
int32_t buffers;
int32_t expect_result;
} buffers[] = {
{ 8, PP_OK },
{ 100, PP_OK },
{ kMaxNumberOfBuffers, PP_OK },
{ -1, PP_ERROR_BADARGUMENT },
{ kMaxNumberOfBuffers + 1, PP_OK }, // Clipped to max value.
{ 0, PP_OK }, // Use default.
};
for (size_t i = 0; i < sizeof(buffers) / sizeof(buffers[0]); ++i) {
TestCompletionCallback cc_configure(instance_->pp_instance(), false);
int32_t attrib_list[] = {
PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS, buffers[i].buffers,
PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE,
};
cc_configure.WaitForResult(
audio_track_.Configure(attrib_list, cc_configure.GetCallback()));
ASSERT_EQ(buffers[i].expect_result, cc_configure.result());
// Get some buffers. This should also succeed when configure fails.
for (int j = 0; j < kTimes; ++j) {
TestCompletionCallbackWithOutput<pp::AudioBuffer> cc_get_buffer(
instance_->pp_instance(), false);
cc_get_buffer.WaitForResult(
audio_track_.GetBuffer(cc_get_buffer.GetCallback()));
ASSERT_EQ(PP_OK, cc_get_buffer.result());
pp::AudioBuffer buffer = cc_get_buffer.output();
ASSERT_FALSE(buffer.is_null());
ASSERT_TRUE(IsSampleRateValid(buffer.GetSampleRate()));
ASSERT_EQ(buffer.GetSampleSize(), PP_AUDIOBUFFER_SAMPLESIZE_16_BITS);
ASSERT_GE(buffer.GetTimestamp(), timestamp);
timestamp = buffer.GetTimestamp();
ASSERT_GT(buffer.GetDataBufferSize(), 0U);
ASSERT_TRUE(buffer.GetDataBuffer() != NULL);
audio_track_.RecycleBuffer(buffer);
}
}
// Configure should fail while plugin holds buffers.
{
TestCompletionCallbackWithOutput<pp::AudioBuffer> cc_get_buffer(
instance_->pp_instance(), false);
cc_get_buffer.WaitForResult(
audio_track_.GetBuffer(cc_get_buffer.GetCallback()));
ASSERT_EQ(PP_OK, cc_get_buffer.result());
pp::AudioBuffer buffer = cc_get_buffer.output();
int32_t attrib_list[] = {
PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS, 0,
PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE,
};
TestCompletionCallback cc_configure(instance_->pp_instance(), false);
cc_configure.WaitForResult(
audio_track_.Configure(attrib_list, cc_configure.GetCallback()));
ASSERT_EQ(PP_ERROR_INPROGRESS, cc_configure.result());
audio_track_.RecycleBuffer(buffer);
}
// Close the track.
audio_track_.Close();
ASSERT_TRUE(audio_track_.HasEnded());
audio_track_ = pp::MediaStreamAudioTrack();
PASS();
}
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef PAPPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_ #ifndef PPAPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_
#define PAPPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_ #define PPAPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_
#include <string> #include <string>
...@@ -26,10 +26,11 @@ class TestMediaStreamAudioTrack : public TestCase { ...@@ -26,10 +26,11 @@ class TestMediaStreamAudioTrack : public TestCase {
std::string TestCreate(); std::string TestCreate();
std::string TestGetBuffer(); std::string TestGetBuffer();
std::string TestConfigure();
pp::MediaStreamAudioTrack audio_track_; pp::MediaStreamAudioTrack audio_track_;
NestedEvent event_; NestedEvent event_;
}; };
#endif // PAPPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_ #endif // PPAPI_TESTS_TEST_MEDIA_STREAM_AUDIO_TRACK_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment