summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authorpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-06 02:50:23 +0000
committerpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-06 02:50:23 +0000
commit2b7a6d39afde5917e8ccb341afdccb0a931b2636 (patch)
tree1074e567377cd34157c0755582d68143fbf040e8 /ppapi
parent8fa42fb71833ddd618b2d9c41b1ccf1a269f7e86 (diff)
downloadchromium_src-2b7a6d39afde5917e8ccb341afdccb0a931b2636.zip
chromium_src-2b7a6d39afde5917e8ccb341afdccb0a931b2636.tar.gz
chromium_src-2b7a6d39afde5917e8ccb341afdccb0a931b2636.tar.bz2
[PPAPI] Pepper MediaStream API audio track implementation and example.
TBR=jamesr@chromium.org BUG=330851 Review URL: https://codereview.chromium.org/140783004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249245 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/api/ppb_audio_frame.idl12
-rw-r--r--ppapi/c/ppb_audio_frame.h12
-rw-r--r--ppapi/cpp/audio_frame.cc10
-rw-r--r--ppapi/cpp/audio_frame.h7
-rw-r--r--ppapi/examples/media_stream_audio/media_stream_audio.cc224
-rw-r--r--ppapi/examples/media_stream_audio/media_stream_audio.html44
-rw-r--r--ppapi/ppapi_proxy.gypi4
-rw-r--r--ppapi/ppapi_tests.gypi10
-rw-r--r--ppapi/proxy/audio_frame_resource.cc111
-rw-r--r--ppapi/proxy/audio_frame_resource.h54
-rw-r--r--ppapi/proxy/media_stream_audio_track_resource.cc148
-rw-r--r--ppapi/proxy/media_stream_audio_track_resource.h70
-rw-r--r--ppapi/proxy/media_stream_video_track_resource.cc18
-rw-r--r--ppapi/proxy/plugin_var_tracker.cc19
-rw-r--r--ppapi/proxy/ppapi_messages.h6
-rw-r--r--ppapi/shared_impl/media_stream_frame.h14
-rw-r--r--ppapi/thunk/ppb_audio_frame_api.h9
-rw-r--r--ppapi/thunk/ppb_audio_frame_thunk.cc11
-rw-r--r--ppapi/thunk/ppb_media_stream_audio_track_thunk.cc2
-rw-r--r--ppapi/thunk/ppb_video_frame_api.h2
20 files changed, 769 insertions, 18 deletions
diff --git a/ppapi/api/ppb_audio_frame.idl b/ppapi/api/ppb_audio_frame.idl
index 6600716..bb4d4b8 100644
--- a/ppapi/api/ppb_audio_frame.idl
+++ b/ppapi/api/ppb_audio_frame.idl
@@ -19,6 +19,7 @@ label Chrome {
*/
enum PP_AudioFrame_SampleRate {
PP_AUDIOFRAME_SAMPLERATE_UNKNOWN = 0,
+ PP_AUDIOFRAME_SAMPLERATE_8000 = 8000,
PP_AUDIOFRAME_SAMPLERATE_44100 = 44100
};
@@ -66,6 +67,17 @@ interface PPB_AudioFrame {
void SetTimestamp([in] PP_Resource frame, [in] PP_TimeDelta timestamp);
/**
+ * Gets the sample rate of the audio frame.
+ *
+ * @param[in] frame A <code>PP_Resource</code> corresponding to an audio frame
+ * resource.
+ *
+ * @return The sample rate of the audio frame.
+ */
+ [on_failure=PP_AUDIOFRAME_SAMPLERATE_UNKNOWN]
+ PP_AudioFrame_SampleRate GetSampleRate([in] PP_Resource frame);
+
+ /**
* Gets the sample size of the audio frame.
*
* @param[in] frame A <code>PP_Resource</code> corresponding to an audio frame
diff --git a/ppapi/c/ppb_audio_frame.h b/ppapi/c/ppb_audio_frame.h
index 095a3ab..03265c4 100644
--- a/ppapi/c/ppb_audio_frame.h
+++ b/ppapi/c/ppb_audio_frame.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* From ppb_audio_frame.idl modified Wed Jan 22 21:25:31 2014. */
+/* From ppb_audio_frame.idl modified Wed Jan 29 13:24:24 2014. */
#ifndef PPAPI_C_PPB_AUDIO_FRAME_H_
#define PPAPI_C_PPB_AUDIO_FRAME_H_
@@ -31,6 +31,7 @@
*/
typedef enum {
PP_AUDIOFRAME_SAMPLERATE_UNKNOWN = 0,
+ PP_AUDIOFRAME_SAMPLERATE_8000 = 8000,
PP_AUDIOFRAME_SAMPLERATE_44100 = 44100
} PP_AudioFrame_SampleRate;
@@ -81,6 +82,15 @@ struct PPB_AudioFrame_0_1 { /* dev */
*/
void (*SetTimestamp)(PP_Resource frame, PP_TimeDelta timestamp);
/**
+ * Gets the sample rate of the audio frame.
+ *
+ * @param[in] frame A <code>PP_Resource</code> corresponding to an audio frame
+ * resource.
+ *
+ * @return The sample rate of the audio frame.
+ */
+ PP_AudioFrame_SampleRate (*GetSampleRate)(PP_Resource frame);
+ /**
* Gets the sample size of the audio frame.
*
* @param[in] frame A <code>PP_Resource</code> corresponding to an audio frame
diff --git a/ppapi/cpp/audio_frame.cc b/ppapi/cpp/audio_frame.cc
index 7c3a1bb..feb038a 100644
--- a/ppapi/cpp/audio_frame.cc
+++ b/ppapi/cpp/audio_frame.cc
@@ -44,10 +44,16 @@ void AudioFrame::SetTimestamp(PP_TimeDelta timestamp) {
get_interface<PPB_AudioFrame_0_1>()->SetTimestamp(pp_resource(), timestamp);
}
-uint32_t AudioFrame::GetSampleSize() const {
+PP_AudioFrame_SampleRate AudioFrame::GetSampleRate() const {
+ if (has_interface<PPB_AudioFrame_0_1>())
+ return get_interface<PPB_AudioFrame_0_1>()->GetSampleRate(pp_resource());
+ return PP_AUDIOFRAME_SAMPLERATE_UNKNOWN;
+}
+
+PP_AudioFrame_SampleSize AudioFrame::GetSampleSize() const {
if (has_interface<PPB_AudioFrame_0_1>())
return get_interface<PPB_AudioFrame_0_1>()->GetSampleSize(pp_resource());
- return 0;
+ return PP_AUDIOFRAME_SAMPLESIZE_UNKNOWN;
}
uint32_t AudioFrame::GetNumberOfChannels() const {
diff --git a/ppapi/cpp/audio_frame.h b/ppapi/cpp/audio_frame.h
index 32d5595..485d814 100644
--- a/ppapi/cpp/audio_frame.h
+++ b/ppapi/cpp/audio_frame.h
@@ -47,10 +47,15 @@ class AudioFrame : public Resource {
/// audio stream.
void SetTimestamp(PP_TimeDelta timestamp);
+ /// Gets the sample rate of the audio frame.
+ ///
+ /// @return The sample rate of the audio frame.
+ PP_AudioFrame_SampleRate GetSampleRate() const;
+
/// Gets the sample size of the audio frame in bytes.
///
/// @return The sample size of the audio frame in bytes.
- uint32_t GetSampleSize() const;
+ PP_AudioFrame_SampleSize GetSampleSize() const;
/// Gets the number of channels in the audio frame.
///
diff --git a/ppapi/examples/media_stream_audio/media_stream_audio.cc b/ppapi/examples/media_stream_audio/media_stream_audio.cc
new file mode 100644
index 0000000..72c6ba8
--- /dev/null
+++ b/ppapi/examples/media_stream_audio/media_stream_audio.cc
@@ -0,0 +1,224 @@
+// 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 <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "ppapi/cpp/audio_frame.h"
+#include "ppapi/cpp/dev/var_resource_dev.h"
+#include "ppapi/cpp/graphics_2d.h"
+#include "ppapi/cpp/image_data.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/logging.h"
+#include "ppapi/cpp/media_stream_audio_track.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+// When compiling natively on Windows, PostMessage can be #define-d to
+// something else.
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+// This example demonstrates receiving audio samples from an AndioMediaTrack
+// and visualizing them.
+
+namespace {
+
+const uint32_t kColorRed = 0xFFFF0000;
+const uint32_t kColorGreen = 0xFF00FF00;
+const uint32_t kColorGrey1 = 0xFF202020;
+const uint32_t kColorGrey2 = 0xFF404040;
+const uint32_t kColorGrey3 = 0xFF606060;
+
+class MediaStreamAudioInstance : public pp::Instance {
+ public:
+ explicit MediaStreamAudioInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ callback_factory_(this),
+ first_frame_(true),
+ sample_count_(0),
+ channel_count_(0),
+ timer_interval_(0),
+ pending_paint_(false),
+ waiting_for_flush_completion_(false) {
+ }
+
+ virtual ~MediaStreamAudioInstance() {
+ }
+
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
+ if (position.size() == size_)
+ return;
+
+ size_ = position.size();
+ device_context_ = pp::Graphics2D(this, size_, false);
+ if (!BindGraphics(device_context_))
+ return;
+
+ Paint();
+ }
+
+ virtual void HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_dictionary())
+ return;
+ pp::VarDictionary var_dictionary_message(var_message);
+ pp::Var var_track = var_dictionary_message.Get("track");
+ if (!var_track.is_resource())
+ return;
+
+ pp::Resource resource_track = pp::VarResource_Dev(var_track).AsResource();
+ audio_track_ = pp::MediaStreamAudioTrack(resource_track);
+ audio_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
+ &MediaStreamAudioInstance::OnGetFrame));
+ }
+
+ private:
+ void ScheduleNextTimer() {
+ PP_DCHECK(timer_interval_ > 0);
+ pp::Module::Get()->core()->CallOnMainThread(
+ timer_interval_,
+ callback_factory_.NewCallback(&MediaStreamAudioInstance::OnTimer),
+ 0);
+ }
+
+ void OnTimer(int32_t) {
+ ScheduleNextTimer();
+ Paint();
+ }
+
+ void DidFlush(int32_t result) {
+ waiting_for_flush_completion_ = false;
+ if (pending_paint_)
+ Paint();
+ }
+
+ void Paint() {
+ if (waiting_for_flush_completion_) {
+ pending_paint_ = true;
+ return;
+ }
+
+ pending_paint_ = false;
+
+ if (size_.IsEmpty())
+ return; // Nothing to do.
+
+ pp::ImageData image = PaintImage(size_);
+ if (!image.is_null()) {
+ device_context_.ReplaceContents(&image);
+ waiting_for_flush_completion_ = true;
+ device_context_.Flush(
+ callback_factory_.NewCallback(&MediaStreamAudioInstance::DidFlush));
+ }
+ }
+
+ pp::ImageData PaintImage(const pp::Size& size) {
+ pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
+ if (image.is_null())
+ return image;
+
+ // Clear to dark grey.
+ for (int y = 0; y < size.height(); y++) {
+ for (int x = 0; x < size.width(); x++)
+ *image.GetAddr32(pp::Point(x, y)) = kColorGrey1;
+ }
+
+ int mid_height = size.height() / 2;
+ int max_amplitude = size.height() * 4 / 10;
+
+ // Draw some lines.
+ for (int x = 0; x < size.width(); x++) {
+ *image.GetAddr32(pp::Point(x, mid_height)) = kColorGrey3;
+ *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = kColorGrey2;
+ *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = kColorGrey2;
+ }
+
+
+ // Draw our samples.
+ for (int x = 0, i = 0;
+ x < std::min(size.width(), static_cast<int>(sample_count_));
+ x++, i += channel_count_) {
+ for (uint32_t ch = 0; ch < std::min(channel_count_, 2U); ++ch) {
+ int y = samples_[i + ch] * max_amplitude /
+ (std::numeric_limits<int16_t>::max() + 1) + mid_height;
+ *image.GetAddr32(pp::Point(x, y)) = (ch == 0 ? kColorRed : kColorGreen);
+ }
+ }
+
+ return image;
+ }
+
+ // Callback that is invoked when new frames are received.
+ void OnGetFrame(int32_t result, pp::AudioFrame frame) {
+ if (result != PP_OK)
+ return;
+
+ PP_DCHECK(frame.GetSampleSize() == PP_AUDIOFRAME_SAMPLESIZE_16_BITS);
+ const char* data = static_cast<const char*>(frame.GetDataBuffer());
+ uint32_t channels = frame.GetNumberOfChannels();
+ uint32_t samples = frame.GetNumberOfSamples() / channels;
+
+ if (channel_count_ != channels || sample_count_ != samples) {
+ channel_count_ = channels;
+ sample_count_ = samples;
+
+ samples_.resize(sample_count_ * channel_count_);
+ timer_interval_ = (sample_count_ * 1000) / frame.GetSampleRate() + 5;
+ // Start the timer for the first frame.
+ if (first_frame_) {
+ first_frame_ = false;
+ ScheduleNextTimer();
+ }
+ }
+
+ memcpy(samples_.data(), data,
+ sample_count_ * channel_count_ * sizeof(int16_t));
+
+ audio_track_.RecycleFrame(frame);
+ audio_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
+ &MediaStreamAudioInstance::OnGetFrame));
+
+ }
+
+ pp::MediaStreamAudioTrack audio_track_;
+ pp::CompletionCallbackFactory<MediaStreamAudioInstance> callback_factory_;
+
+ bool first_frame_;
+ uint32_t sample_count_;
+ uint32_t channel_count_;
+ std::vector<int16_t> samples_;
+
+ int32_t timer_interval_;
+
+ // Painting stuff.
+ pp::Size size_;
+ pp::Graphics2D device_context_;
+ bool pending_paint_;
+ bool waiting_for_flush_completion_;
+};
+
+class MediaStreamAudioModule : public pp::Module {
+ public:
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new MediaStreamAudioInstance(instance);
+ }
+};
+
+} // namespace
+
+namespace pp {
+
+// Factory function for your specialization of the Module object.
+Module* CreateModule() {
+ return new MediaStreamAudioModule();
+}
+
+} // namespace pp
diff --git a/ppapi/examples/media_stream_audio/media_stream_audio.html b/ppapi/examples/media_stream_audio/media_stream_audio.html
new file mode 100644
index 0000000..6513ccd
--- /dev/null
+++ b/ppapi/examples/media_stream_audio/media_stream_audio.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ 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.
+ -->
+<head>
+ <title>Media Stream Audio Example</title>
+ <script type="text/javascript">
+ var plugin;
+ var stream;
+
+ function handleMessage(message) {
+ console.log(message);
+ }
+
+ function success(s) {
+ stream = s;
+ plugin.postMessage({track: stream.getAudioTracks()[0]});
+ }
+
+ function failure(e) {
+ console.log(e);
+ }
+
+ function initialize() {
+ plugin = document.getElementById('plugin');
+ plugin.addEventListener('message', handleMessage, false);
+ navigator.webkitGetUserMedia({ 'audio': true }, success, failure);
+ }
+
+ document.addEventListener('DOMContentLoaded', initialize, false);
+ </script>
+</head>
+
+<body>
+ <h1>Pepper MediaStream Audio API Example</h1><br>
+ This example demonstrates receiving frames from an audio MediaStreamTrack and
+ rendering them in a plugin.<br>
+ <embed id="plugin" type="application/x-ppapi-example-media-stream-audio"
+ width="320" height="240"/>
+</body>
+</html>
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi
index fe357d7..c136287 100644
--- a/ppapi/ppapi_proxy.gypi
+++ b/ppapi/ppapi_proxy.gypi
@@ -19,6 +19,8 @@
'cpp/completion_callback.h',
'utility/completion_callback_factory.h',
+ 'proxy/audio_frame_resource.cc',
+ 'proxy/audio_frame_resource.h',
'proxy/audio_input_resource.cc',
'proxy/audio_input_resource.h',
'proxy/broker_dispatcher.cc',
@@ -84,6 +86,8 @@
'proxy/isolated_file_system_private_resource.cc',
'proxy/isolated_file_system_private_resource.h',
'proxy/locking_resource_releaser.h',
+ 'proxy/media_stream_audio_track_resource.cc',
+ 'proxy/media_stream_audio_track_resource.h',
'proxy/media_stream_track_resource_base.cc',
'proxy/media_stream_track_resource_base.h',
'proxy/media_stream_video_track_resource.cc',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 1d2b3b8..ba3a2ff 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -524,6 +524,16 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
+ 'target_name': 'ppapi_example_media_stream_audio',
+ 'dependencies': [
+ 'ppapi_example_skeleton',
+ 'ppapi.gyp:ppapi_cpp',
+ ],
+ 'sources': [
+ 'examples/media_stream_audio/media_stream_audio.cc',
+ ],
+ },
+ {
'target_name': 'ppapi_example_media_stream_video',
'dependencies': [
'ppapi_example_skeleton',
diff --git a/ppapi/proxy/audio_frame_resource.cc b/ppapi/proxy/audio_frame_resource.cc
new file mode 100644
index 0000000..4954857
--- /dev/null
+++ b/ppapi/proxy/audio_frame_resource.cc
@@ -0,0 +1,111 @@
+// 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/proxy/audio_frame_resource.h"
+
+#include "base/logging.h"
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/shared_impl/var.h"
+
+namespace ppapi {
+namespace proxy {
+
+AudioFrameResource::AudioFrameResource(PP_Instance instance,
+ int32_t index,
+ MediaStreamFrame* frame)
+ : Resource(OBJECT_IS_PROXY, instance),
+ index_(index),
+ frame_(frame) {
+ DCHECK_EQ(frame_->header.type, MediaStreamFrame::TYPE_AUDIO);
+}
+
+AudioFrameResource::~AudioFrameResource() {
+ CHECK(!frame_) << "An unused (or unrecycled) frame is destroyed.";
+}
+
+thunk::PPB_AudioFrame_API* AudioFrameResource::AsPPB_AudioFrame_API() {
+ return this;
+}
+
+PP_TimeDelta AudioFrameResource::GetTimestamp() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return 0.0;
+ }
+ return frame_->audio.timestamp;
+}
+
+void AudioFrameResource::SetTimestamp(PP_TimeDelta timestamp) {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return;
+ }
+ frame_->audio.timestamp = timestamp;
+}
+
+PP_AudioFrame_SampleRate AudioFrameResource::GetSampleRate() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return PP_AUDIOFRAME_SAMPLERATE_UNKNOWN;
+ }
+ return frame_->audio.sample_rate;
+}
+
+PP_AudioFrame_SampleSize AudioFrameResource::GetSampleSize() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return PP_AUDIOFRAME_SAMPLESIZE_UNKNOWN;
+ }
+ return PP_AUDIOFRAME_SAMPLESIZE_16_BITS;
+}
+
+uint32_t AudioFrameResource::GetNumberOfChannels() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return 0;
+ }
+ return frame_->audio.number_of_channels;
+}
+
+uint32_t AudioFrameResource::GetNumberOfSamples() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return 0;
+ }
+ return frame_->audio.number_of_samples;
+}
+
+void* AudioFrameResource::GetDataBuffer() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return NULL;
+ }
+ return frame_->audio.data;
+}
+
+uint32_t AudioFrameResource::GetDataBufferSize() {
+ if (!frame_) {
+ VLOG(1) << "Frame is invalid";
+ return 0;
+ }
+ return frame_->audio.data_size;
+}
+
+MediaStreamFrame* AudioFrameResource::GetFrameBuffer() {
+ return frame_;
+}
+
+int32_t AudioFrameResource::GetFrameBufferIndex() {
+ return index_;
+}
+
+void AudioFrameResource::Invalidate() {
+ DCHECK(frame_);
+ DCHECK_GE(index_, 0);
+ frame_ = NULL;
+ index_ = -1;
+}
+
+} // namespace proxy
+} // namespace ppapi
diff --git a/ppapi/proxy/audio_frame_resource.h b/ppapi/proxy/audio_frame_resource.h
new file mode 100644
index 0000000..a463bba
--- /dev/null
+++ b/ppapi/proxy/audio_frame_resource.h
@@ -0,0 +1,54 @@
+// 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_PROXY_AUDIO_FRAME_RESOURCE_H_
+#define PPAPI_PROXY_AUDIO_FRAME_RESOURCE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/media_stream_frame.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_audio_frame_api.h"
+
+namespace ppapi {
+namespace proxy {
+
+class PPAPI_PROXY_EXPORT AudioFrameResource : public Resource,
+ public thunk::PPB_AudioFrame_API {
+ public:
+ AudioFrameResource(PP_Instance instance,
+ int32_t index,
+ MediaStreamFrame* frame);
+
+ virtual ~AudioFrameResource();
+
+ // PluginResource overrides:
+ virtual thunk::PPB_AudioFrame_API* AsPPB_AudioFrame_API() OVERRIDE;
+
+ // PPB_AudioFrame_API overrides:
+ virtual PP_TimeDelta GetTimestamp() OVERRIDE;
+ virtual void SetTimestamp(PP_TimeDelta timestamp) OVERRIDE;
+ virtual PP_AudioFrame_SampleRate GetSampleRate() OVERRIDE;
+ virtual PP_AudioFrame_SampleSize GetSampleSize() OVERRIDE;
+ virtual uint32_t GetNumberOfChannels() OVERRIDE;
+ virtual uint32_t GetNumberOfSamples() OVERRIDE;
+ virtual void* GetDataBuffer() OVERRIDE;
+ virtual uint32_t GetDataBufferSize() OVERRIDE;
+ virtual MediaStreamFrame* GetFrameBuffer();
+ virtual int32_t GetFrameBufferIndex();
+ virtual void Invalidate();
+
+ // Frame index
+ int32_t index_;
+
+ MediaStreamFrame* frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioFrameResource);
+};
+
+} // namespace proxy
+} // namespace ppapi
+
+#endif // PPAPI_PROXY_AUDIO_FRAME_RESOURCE_H_
diff --git a/ppapi/proxy/media_stream_audio_track_resource.cc b/ppapi/proxy/media_stream_audio_track_resource.cc
new file mode 100644
index 0000000..10956ab
--- /dev/null
+++ b/ppapi/proxy/media_stream_audio_track_resource.cc
@@ -0,0 +1,148 @@
+// 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/proxy/media_stream_audio_track_resource.h"
+
+#include "ppapi/proxy/audio_frame_resource.h"
+#include "ppapi/shared_impl/media_stream_frame.h"
+#include "ppapi/shared_impl/var.h"
+
+namespace ppapi {
+namespace proxy {
+
+MediaStreamAudioTrackResource::MediaStreamAudioTrackResource(
+ Connection connection,
+ PP_Instance instance,
+ int pending_renderer_id,
+ const std::string& id)
+ : MediaStreamTrackResourceBase(
+ connection, instance, pending_renderer_id, id),
+ get_frame_output_(NULL) {
+}
+
+MediaStreamAudioTrackResource::~MediaStreamAudioTrackResource() {
+ Close();
+}
+
+thunk::PPB_MediaStreamAudioTrack_API*
+MediaStreamAudioTrackResource::AsPPB_MediaStreamAudioTrack_API() {
+ return this;
+}
+
+PP_Var MediaStreamAudioTrackResource::GetId() {
+ return StringVar::StringToPPVar(id());
+}
+
+PP_Bool MediaStreamAudioTrackResource::HasEnded() {
+ return PP_FromBool(has_ended());
+}
+
+int32_t MediaStreamAudioTrackResource::Configure(
+ const int32_t attrib_list[],
+ scoped_refptr<TrackedCallback> callback) {
+ // TODO(penghuang): Implement this function.
+ return PP_ERROR_NOTSUPPORTED;
+}
+
+int32_t MediaStreamAudioTrackResource::GetAttrib(
+ PP_MediaStreamAudioTrack_Attrib attrib,
+ int32_t* value) {
+ // TODO(penghuang): Implement this function.
+ return PP_ERROR_NOTSUPPORTED;
+}
+
+int32_t MediaStreamAudioTrackResource::GetFrame(
+ PP_Resource* frame,
+ scoped_refptr<TrackedCallback> callback) {
+ if (has_ended())
+ return PP_ERROR_FAILED;
+
+ if (TrackedCallback::IsPending(get_frame_callback_))
+ return PP_ERROR_INPROGRESS;
+
+ *frame = GetAudioFrame();
+ if (*frame)
+ return PP_OK;
+
+ // TODO(penghuang): Use the callback as hints to determine which thread will
+ // use the resource, so we could deliver frames to the target thread directly
+ // for better performance.
+ get_frame_output_ = frame;
+ get_frame_callback_ = callback;
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t MediaStreamAudioTrackResource::RecycleFrame(PP_Resource frame) {
+ FrameMap::iterator it = frames_.find(frame);
+ if (it == frames_.end())
+ return PP_ERROR_BADRESOURCE;
+
+ scoped_refptr<AudioFrameResource> frame_resource = it->second;
+ frames_.erase(it);
+
+ if (has_ended())
+ return PP_OK;
+
+ DCHECK_GE(frame_resource->GetFrameBufferIndex(), 0);
+
+ SendEnqueueFrameMessageToHost(frame_resource->GetFrameBufferIndex());
+ frame_resource->Invalidate();
+ return PP_OK;
+}
+
+void MediaStreamAudioTrackResource::Close() {
+ if (has_ended())
+ return;
+
+ if (TrackedCallback::IsPending(get_frame_callback_)) {
+ *get_frame_output_ = 0;
+ get_frame_callback_->PostAbort();
+ get_frame_callback_ = NULL;
+ get_frame_output_ = 0;
+ }
+
+ ReleaseFrames();
+ MediaStreamTrackResourceBase::CloseInternal();
+}
+
+void MediaStreamAudioTrackResource::OnNewFrameEnqueued() {
+ if (!TrackedCallback::IsPending(get_frame_callback_))
+ return;
+
+ *get_frame_output_ = GetAudioFrame();
+ int32_t result = *get_frame_output_ ? PP_OK : PP_ERROR_FAILED;
+ get_frame_output_ = NULL;
+ scoped_refptr<TrackedCallback> callback;
+ callback.swap(get_frame_callback_);
+ callback->Run(result);
+}
+
+PP_Resource MediaStreamAudioTrackResource::GetAudioFrame() {
+ int32_t index = frame_buffer()->DequeueFrame();
+ if (index < 0)
+ return 0;
+
+ MediaStreamFrame* frame = frame_buffer()->GetFramePointer(index);
+ DCHECK(frame);
+ scoped_refptr<AudioFrameResource> resource =
+ new AudioFrameResource(pp_instance(), index, frame);
+ // Add |pp_resource()| and |resource| into |frames_|.
+ // |frames_| uses scoped_ptr<> to hold a ref of |resource|. It keeps the
+ // resource alive.
+ frames_.insert(FrameMap::value_type(resource->pp_resource(), resource));
+ return resource->GetReference();
+}
+
+void MediaStreamAudioTrackResource::ReleaseFrames() {
+ FrameMap::iterator it = frames_.begin();
+ while (it != frames_.end()) {
+ // Just invalidate and release VideoFrameResorce, but keep PP_Resource.
+ // So plugin can still use |RecycleFrame()|.
+ it->second->Invalidate();
+ it->second = NULL;
+ }
+}
+
+} // namespace proxy
+} // namespace ppapi
diff --git a/ppapi/proxy/media_stream_audio_track_resource.h b/ppapi/proxy/media_stream_audio_track_resource.h
new file mode 100644
index 0000000..2686381
--- /dev/null
+++ b/ppapi/proxy/media_stream_audio_track_resource.h
@@ -0,0 +1,70 @@
+// 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_PROXY_MEDIA_STREAM_AUDIO_TRACK_RESOURCE_H_
+#define PPAPI_PROXY_MEDIA_STREAM_AUDIO_TRACK_RESOURCE_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "ppapi/proxy/media_stream_track_resource_base.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/thunk/ppb_media_stream_audio_track_api.h"
+
+namespace ppapi {
+namespace proxy {
+
+class AudioFrameResource;
+
+class PPAPI_PROXY_EXPORT MediaStreamAudioTrackResource
+ : public MediaStreamTrackResourceBase,
+ public thunk::PPB_MediaStreamAudioTrack_API {
+ public:
+ MediaStreamAudioTrackResource(Connection connection,
+ PP_Instance instance,
+ int pending_renderer_id,
+ const std::string& id);
+
+ virtual ~MediaStreamAudioTrackResource();
+
+ // Resource overrides:
+ virtual thunk::PPB_MediaStreamAudioTrack_API*
+ AsPPB_MediaStreamAudioTrack_API() OVERRIDE;
+
+ // PPB_MediaStreamAudioTrack_API overrides:
+ virtual PP_Var GetId() OVERRIDE;
+ virtual PP_Bool HasEnded() OVERRIDE;
+ virtual int32_t Configure(const int32_t attrib_list[],
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t GetAttrib(PP_MediaStreamAudioTrack_Attrib attrib,
+ int32_t* value) OVERRIDE;
+ virtual int32_t GetFrame(
+ PP_Resource* frame,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t RecycleFrame(PP_Resource frame) OVERRIDE;
+ virtual void Close() OVERRIDE;
+
+ // MediaStreamFrameBuffer::Delegate overrides:
+ virtual void OnNewFrameEnqueued() OVERRIDE;
+
+ private:
+ PP_Resource GetAudioFrame();
+
+ void ReleaseFrames();
+
+ // Allocated frame resources by |GetFrame()|.
+ typedef std::map<PP_Resource, scoped_refptr<AudioFrameResource> > FrameMap;
+ FrameMap frames_;
+
+ PP_Resource* get_frame_output_;
+
+ scoped_refptr<TrackedCallback> get_frame_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioTrackResource);
+};
+
+} // namespace proxy
+} // namespace ppapi
+
+#endif // PPAPI_PROXY_MEDIA_STREAM_AUDIO_TRACK_RESOURCE_H_
diff --git a/ppapi/proxy/media_stream_video_track_resource.cc b/ppapi/proxy/media_stream_video_track_resource.cc
index e8ab4c5..804df00 100644
--- a/ppapi/proxy/media_stream_video_track_resource.cc
+++ b/ppapi/proxy/media_stream_video_track_resource.cc
@@ -107,20 +107,24 @@ void MediaStreamVideoTrackResource::Close() {
}
void MediaStreamVideoTrackResource::OnNewFrameEnqueued() {
- if (TrackedCallback::IsPending(get_frame_callback_)) {
- *get_frame_output_ = GetVideoFrame();
- get_frame_output_ = NULL;
- scoped_refptr<TrackedCallback> callback;
- callback.swap(get_frame_callback_);
- callback->Run(PP_OK);
- }
+ if (!TrackedCallback::IsPending(get_frame_callback_))
+ return;
+
+ *get_frame_output_ = GetVideoFrame();
+ int32_t result = *get_frame_output_ ? PP_OK : PP_ERROR_FAILED;
+ get_frame_output_ = NULL;
+ scoped_refptr<TrackedCallback> callback;
+ callback.swap(get_frame_callback_);
+ callback->Run(result);
}
PP_Resource MediaStreamVideoTrackResource::GetVideoFrame() {
int32_t index = frame_buffer()->DequeueFrame();
if (index < 0)
return 0;
+
MediaStreamFrame* frame = frame_buffer()->GetFramePointer(index);
+ DCHECK(frame);
scoped_refptr<VideoFrameResource> resource =
new VideoFrameResource(pp_instance(), index, frame);
// Add |pp_resource()| and |resource| into |frames_|.
diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc
index e2db871..06db224 100644
--- a/ppapi/proxy/plugin_var_tracker.cc
+++ b/ppapi/proxy/plugin_var_tracker.cc
@@ -10,6 +10,7 @@
#include "ppapi/c/dev/ppp_class_deprecated.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/file_system_resource.h"
+#include "ppapi/proxy/media_stream_audio_track_resource.h"
#include "ppapi/proxy/media_stream_video_track_resource.h"
#include "ppapi/proxy/plugin_array_buffer_var.h"
#include "ppapi/proxy/plugin_dispatcher.h"
@@ -195,6 +196,24 @@ PP_Var PluginVarTracker::MakeResourcePPVarFromMessage(
file_system_type))->GetReference();
return MakeResourcePPVar(pp_resource);
}
+ case PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost::ID: {
+ DCHECK(pending_renderer_id);
+ std::string track_id;
+ if (!UnpackMessage<
+ PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost>(
+ creation_message, &track_id)) {
+ NOTREACHED() <<
+ "Invalid message of type "
+ "PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost";
+ return PP_MakeNull();
+ }
+ PP_Resource pp_resource =
+ (new MediaStreamAudioTrackResource(GetConnectionForInstance(instance),
+ instance,
+ pending_renderer_id,
+ track_id))->GetReference();
+ return MakeResourcePPVar(pp_resource);
+ }
case PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost::ID: {
DCHECK(pending_renderer_id);
std::string track_id;
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 7e6543e..92ed096 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1437,9 +1437,13 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply,
std::string /* fsid */)
// MediaStream -----------------------------------------------------------------
-// Message for init frames. It also takes a shared memory handle.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost,
+ std::string /* track_id */)
IPC_MESSAGE_CONTROL1(PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost,
std::string /* track_id */)
+
+// Message for init frames. It also takes a shared memory handle which is put in
+// the outer ResourceReplyMessage.
IPC_MESSAGE_CONTROL2(PpapiPluginMsg_MediaStreamTrack_InitFrames,
int32_t /* number_of_frames */,
int32_t /* frame_size */)
diff --git a/ppapi/shared_impl/media_stream_frame.h b/ppapi/shared_impl/media_stream_frame.h
index b3ec8bb2..72eeef9 100644
--- a/ppapi/shared_impl/media_stream_frame.h
+++ b/ppapi/shared_impl/media_stream_frame.h
@@ -5,6 +5,7 @@
#ifndef PPAPI_SHARED_IMPL_MEDIA_STREAM_FRAME_H_
#define PPAPI_SHARED_IMPL_MEDIA_STREAM_FRAME_H_
+#include "ppapi/c/ppb_audio_frame.h"
#include "ppapi/c/ppb_video_frame.h"
namespace ppapi {
@@ -23,7 +24,14 @@ union MediaStreamFrame {
struct Audio {
Header header;
- // TODO(penghuang): implement the audio frame.
+ PP_TimeDelta timestamp;
+ PP_AudioFrame_SampleRate sample_rate;
+ uint32_t number_of_channels;
+ uint32_t number_of_samples;
+ uint32_t data_size;
+ // Uses 8 bytes to make sure the Audio struct has consistent size between
+ // NaCl code and renderer code.
+ uint8_t data[8];
};
struct Video {
@@ -33,7 +41,7 @@ union MediaStreamFrame {
PP_Size size;
uint32_t data_size;
// Uses 8 bytes to make sure the Video struct has consistent size between
- // Nacl code and renderer code.
+ // NaCl code and renderer code.
uint8_t data[8];
};
@@ -41,7 +49,7 @@ union MediaStreamFrame {
// the size and alighment to be consistent between NaCl and its host trusted
// platform.
PP_COMPILE_ASSERT_SIZE_IN_BYTES(Header, 8);
- PP_COMPILE_ASSERT_SIZE_IN_BYTES(Audio, 8);
+ PP_COMPILE_ASSERT_SIZE_IN_BYTES(Audio, 40);
PP_COMPILE_ASSERT_SIZE_IN_BYTES(Video, 40);
Header header;
diff --git a/ppapi/thunk/ppb_audio_frame_api.h b/ppapi/thunk/ppb_audio_frame_api.h
index 21c4d71..ca9cd1f 100644
--- a/ppapi/thunk/ppb_audio_frame_api.h
+++ b/ppapi/thunk/ppb_audio_frame_api.h
@@ -9,6 +9,9 @@
#include "ppapi/thunk/ppapi_thunk_export.h"
namespace ppapi {
+
+union MediaStreamFrame;
+
namespace thunk {
class PPAPI_THUNK_EXPORT PPB_AudioFrame_API {
@@ -16,11 +19,17 @@ class PPAPI_THUNK_EXPORT PPB_AudioFrame_API {
virtual ~PPB_AudioFrame_API() {}
virtual PP_TimeDelta GetTimestamp() = 0;
virtual void SetTimestamp(PP_TimeDelta timestamp) = 0;
+ virtual PP_AudioFrame_SampleRate GetSampleRate() = 0;
virtual PP_AudioFrame_SampleSize GetSampleSize() = 0;
virtual uint32_t GetNumberOfChannels() = 0;
virtual uint32_t GetNumberOfSamples() = 0;
virtual void* GetDataBuffer() = 0;
virtual uint32_t GetDataBufferSize() = 0;
+
+ // Methods used by Pepper internal implementation only.
+ virtual MediaStreamFrame* GetFrameBuffer() = 0;
+ virtual int32_t GetFrameBufferIndex() = 0;
+ virtual void Invalidate() = 0;
};
} // namespace thunk
diff --git a/ppapi/thunk/ppb_audio_frame_thunk.cc b/ppapi/thunk/ppb_audio_frame_thunk.cc
index 18cfdc4..692af87 100644
--- a/ppapi/thunk/ppb_audio_frame_thunk.cc
+++ b/ppapi/thunk/ppb_audio_frame_thunk.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// From ppb_audio_frame.idl modified Wed Jan 22 09:11:35 2014.
+// From ppb_audio_frame.idl modified Thu Jan 23 15:09:57 2014.
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppb_audio_frame.h"
@@ -38,6 +38,14 @@ void SetTimestamp(PP_Resource frame, PP_TimeDelta timestamp) {
enter.object()->SetTimestamp(timestamp);
}
+PP_AudioFrame_SampleRate GetSampleRate(PP_Resource frame) {
+ VLOG(4) << "PPB_AudioFrame::GetSampleRate()";
+ EnterResource<PPB_AudioFrame_API> enter(frame, true);
+ if (enter.failed())
+ return PP_AUDIOFRAME_SAMPLERATE_UNKNOWN;
+ return enter.object()->GetSampleRate();
+}
+
PP_AudioFrame_SampleSize GetSampleSize(PP_Resource frame) {
VLOG(4) << "PPB_AudioFrame::GetSampleSize()";
EnterResource<PPB_AudioFrame_API> enter(frame, true);
@@ -82,6 +90,7 @@ const PPB_AudioFrame_0_1 g_ppb_audioframe_thunk_0_1 = {
&IsAudioFrame,
&GetTimestamp,
&SetTimestamp,
+ &GetSampleRate,
&GetSampleSize,
&GetNumberOfChannels,
&GetNumberOfSamples,
diff --git a/ppapi/thunk/ppb_media_stream_audio_track_thunk.cc b/ppapi/thunk/ppb_media_stream_audio_track_thunk.cc
index 34e4937..93a2829 100644
--- a/ppapi/thunk/ppb_media_stream_audio_track_thunk.cc
+++ b/ppapi/thunk/ppb_media_stream_audio_track_thunk.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// From ppb_media_stream_audio_track.idl modified Thu Jan 23 08:57:17 2014.
+// From ppb_media_stream_audio_track.idl modified Thu Jan 23 15:04:50 2014.
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
diff --git a/ppapi/thunk/ppb_video_frame_api.h b/ppapi/thunk/ppb_video_frame_api.h
index 9a08882..d3c46b8 100644
--- a/ppapi/thunk/ppb_video_frame_api.h
+++ b/ppapi/thunk/ppb_video_frame_api.h
@@ -24,7 +24,7 @@ class PPAPI_THUNK_EXPORT PPB_VideoFrame_API {
virtual void* GetDataBuffer() = 0;
virtual uint32_t GetDataBufferSize() = 0;
- // Private APIs:
+ // Methods used by Pepper internal implementation only.
virtual MediaStreamFrame* GetFrameBuffer() = 0;
virtual int32_t GetFrameBufferIndex() = 0;
virtual void Invalidate() = 0;