diff options
Diffstat (limited to 'chromium/ppapi/examples/media_stream_audio/media_stream_audio.cc')
-rw-r--r-- | chromium/ppapi/examples/media_stream_audio/media_stream_audio.cc | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/chromium/ppapi/examples/media_stream_audio/media_stream_audio.cc b/chromium/ppapi/examples/media_stream_audio/media_stream_audio.cc new file mode 100644 index 00000000000..1d7bac1748d --- /dev/null +++ b/chromium/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_buffer.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/cpp/var_dictionary.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_buffer_(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 = var_track.AsResource(); + audio_track_ = pp::MediaStreamAudioTrack(resource_track); + audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput( + &MediaStreamAudioInstance::OnGetBuffer)); + } + + 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 buffers are received. + void OnGetBuffer(int32_t result, pp::AudioBuffer buffer) { + if (result != PP_OK) + return; + + PP_DCHECK(buffer.GetSampleSize() == PP_AUDIOBUFFER_SAMPLESIZE_16_BITS); + const char* data = static_cast<const char*>(buffer.GetDataBuffer()); + uint32_t channels = buffer.GetNumberOfChannels(); + uint32_t samples = buffer.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) / buffer.GetSampleRate() + 5; + // Start the timer for the first buffer. + if (first_buffer_) { + first_buffer_ = false; + ScheduleNextTimer(); + } + } + + memcpy(samples_.data(), data, + sample_count_ * channel_count_ * sizeof(int16_t)); + + audio_track_.RecycleBuffer(buffer); + audio_track_.GetBuffer(callback_factory_.NewCallbackWithOutput( + &MediaStreamAudioInstance::OnGetBuffer)); + + } + + pp::MediaStreamAudioTrack audio_track_; + pp::CompletionCallbackFactory<MediaStreamAudioInstance> callback_factory_; + + bool first_buffer_; + 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 |