diff options
author | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-06 02:50:23 +0000 |
---|---|---|
committer | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-06 02:50:23 +0000 |
commit | 2b7a6d39afde5917e8ccb341afdccb0a931b2636 (patch) | |
tree | 1074e567377cd34157c0755582d68143fbf040e8 /ppapi | |
parent | 8fa42fb71833ddd618b2d9c41b1ccf1a269f7e86 (diff) | |
download | chromium_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.idl | 12 | ||||
-rw-r--r-- | ppapi/c/ppb_audio_frame.h | 12 | ||||
-rw-r--r-- | ppapi/cpp/audio_frame.cc | 10 | ||||
-rw-r--r-- | ppapi/cpp/audio_frame.h | 7 | ||||
-rw-r--r-- | ppapi/examples/media_stream_audio/media_stream_audio.cc | 224 | ||||
-rw-r--r-- | ppapi/examples/media_stream_audio/media_stream_audio.html | 44 | ||||
-rw-r--r-- | ppapi/ppapi_proxy.gypi | 4 | ||||
-rw-r--r-- | ppapi/ppapi_tests.gypi | 10 | ||||
-rw-r--r-- | ppapi/proxy/audio_frame_resource.cc | 111 | ||||
-rw-r--r-- | ppapi/proxy/audio_frame_resource.h | 54 | ||||
-rw-r--r-- | ppapi/proxy/media_stream_audio_track_resource.cc | 148 | ||||
-rw-r--r-- | ppapi/proxy/media_stream_audio_track_resource.h | 70 | ||||
-rw-r--r-- | ppapi/proxy/media_stream_video_track_resource.cc | 18 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.cc | 19 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.h | 6 | ||||
-rw-r--r-- | ppapi/shared_impl/media_stream_frame.h | 14 | ||||
-rw-r--r-- | ppapi/thunk/ppb_audio_frame_api.h | 9 | ||||
-rw-r--r-- | ppapi/thunk/ppb_audio_frame_thunk.cc | 11 | ||||
-rw-r--r-- | ppapi/thunk/ppb_media_stream_audio_track_thunk.cc | 2 | ||||
-rw-r--r-- | ppapi/thunk/ppb_video_frame_api.h | 2 |
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; |