15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <stdlib.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/audio_config.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/dev/audio_input_dev.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/dev/device_ref_dev.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/graphics_2d.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/image_data.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/instance.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/logging.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/rect.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/size.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ppapi/utility/threading/lock.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When compiling natively on Windows, PostMessage can be #define-d to
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// something else.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PostMessage
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef PostMessage
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This sample frequency is guaranteed to work.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32_t kSampleCount = 1024;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32_t kChannelCount = 1;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char* const kDelimiter = "#__#";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MyInstance : public pp::Instance {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MyInstance(PP_Instance instance)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : pp::Instance(instance),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_factory_(this),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sample_count_(0),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        channel_count_(0),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        samples_(NULL),
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        latency_(0),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        timer_interval_(0),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_paint_(false),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        waiting_for_flush_completion_(false) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~MyInstance() {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    device_detector_.MonitorDeviceChange(NULL, NULL);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_input_.Close();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // The audio input thread has exited before the previous call returned, so
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // it is safe to do so now.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete[] samples_;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(this,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               kSampleFrequency,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               kSampleCount);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PP_DCHECK(sample_count_ > 0);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_count_ = kChannelCount;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    samples_ = new int16_t[sample_count_ * channel_count_];
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(samples_, 0, sample_count_ * channel_count_ * sizeof(int16_t));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    device_detector_ = pp::AudioInput_Dev(this);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try to ensure that we pick up a new set of samples between each
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // timer-generated repaint.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_interval_ = (sample_count_ * 1000) / kSampleFrequency + 5;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextTimer();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (position.size() == size_)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_ = position.size();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device_context_ = pp::Graphics2D(this, size_, false);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!BindGraphics(device_context_))
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Paint();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void HandleMessage(const pp::Var& message_data) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (message_data.is_string()) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string event = message_data.AsString();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (event == "PageInitialized") {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        int32_t result = device_detector_.MonitorDeviceChange(
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            &MyInstance::MonitorDeviceChangeCallback, this);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (result != PP_OK)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PostMessage(pp::Var("MonitorDeviceChangeFailed"));
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pp::CompletionCallbackWithOutput<std::vector<pp::DeviceRef_Dev> >
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            callback = callback_factory_.NewCallbackWithOutput(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                &MyInstance::EnumerateDevicesFinished);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = device_detector_.EnumerateDevices(callback);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (result != PP_OK_COMPLETIONPENDING)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PostMessage(pp::Var("EnumerationFailed"));
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (event == "UseDefault") {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Open(pp::DeviceRef_Dev());
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (event == "Stop") {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Stop();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (event == "Start") {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Start();
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (event.find("Monitor:") == 0) {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string index_str = event.substr(strlen("Monitor:"));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        int index = atoi(index_str.c_str());
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (index >= 0 && index < static_cast<int>(monitor_devices_.size()))
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          Open(monitor_devices_[index]);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PP_NOTREACHED();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (event.find("Enumerate:") == 0) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string index_str = event.substr(strlen("Enumerate:"));
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        int index = atoi(index_str.c_str());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (index >= 0 && index < static_cast<int>(enumerate_devices_.size()))
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          Open(enumerate_devices_[index]);
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PP_NOTREACHED();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleNextTimer() {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PP_DCHECK(timer_interval_ > 0);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::Module::Get()->core()->CallOnMainThread(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        timer_interval_,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_factory_.NewCallback(&MyInstance::OnTimer),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnTimer(int32_t) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextTimer();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Paint();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DidFlush(int32_t result) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_for_flush_completion_ = false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pending_paint_)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Paint();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Paint() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (waiting_for_flush_completion_) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_paint_ = true;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_paint_ = false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size_.IsEmpty())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;  // Nothing to do.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::ImageData image = PaintImage(size_);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image.is_null()) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_context_.ReplaceContents(&image);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      waiting_for_flush_completion_ = true;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_context_.Flush(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          callback_factory_.NewCallback(&MyInstance::DidFlush));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData PaintImage(const pp::Size& size) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (image.is_null())
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return image;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clear to dark grey.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < size.height(); y++) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int x = 0; x < size.width(); x++)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *image.GetAddr32(pp::Point(x, y)) = 0xff202020;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int mid_height = size.height() / 2;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_amplitude = size.height() * 4 / 10;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Draw some lines.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = 0; x < size.width(); x++) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *image.GetAddr32(pp::Point(x, mid_height)) = 0xff606060;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = 0xff404040;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = 0xff404040;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      pp::AutoLock auto_lock(lock_);
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Draw the latency as a red bar at the bottom.
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      PP_DCHECK(latency_ >= 0);
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int latency_bar_length =
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          latency_ < 1 ? size.width() * latency_ : size.width();
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      for (int x = 0; x < latency_bar_length; ++x) {
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = 0xffff0000;
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Draw our samples.
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      for (int x = 0, i = 0;
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           x < std::min(size.width(), static_cast<int>(sample_count_));
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           x++, i += channel_count_) {
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        int y = samples_[i] * max_amplitude /
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                (std::numeric_limits<int16_t>::max() + 1) + mid_height;
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        *image.GetAddr32(pp::Point(x, y)) = 0xffffffff;
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return image;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Open(const pp::DeviceRef_Dev& device) {
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_input_.Close();
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_input_ = pp::AudioInput_Dev(this);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::AudioConfig config = pp::AudioConfig(this,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             kSampleFrequency,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             sample_count_);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::CompletionCallback callback = callback_factory_.NewCallback(
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &MyInstance::OpenFinished);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32_t result = audio_input_.Open(device, config, CaptureCallback, this,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       callback);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != PP_OK_COMPLETIONPENDING)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var("OpenFailed"));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop() {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!audio_input_.StopCapture())
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var("StopFailed"));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!audio_input_.StartCapture())
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var("StartFailed"));
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EnumerateDevicesFinished(int32_t result,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                std::vector<pp::DeviceRef_Dev>& devices) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == PP_OK) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enumerate_devices_.swap(devices);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string device_names = "Enumerate:";
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t index = 0; index < enumerate_devices_.size(); ++index) {
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pp::Var name = enumerate_devices_[index].GetName();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PP_DCHECK(name.is_string());
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (index != 0)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          device_names += kDelimiter;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        device_names += name.AsString();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var(device_names));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var("EnumerationFailed"));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OpenFinished(int32_t result) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == PP_OK) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!audio_input_.StartCapture())
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PostMessage(pp::Var("StartFailed"));
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PostMessage(pp::Var("OpenFailed"));
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void CaptureCallback(const void* samples,
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              uint32_t num_bytes,
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              PP_TimeDelta latency,
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              void* ctx) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MyInstance* thiz = static_cast<MyInstance*>(ctx);
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    pp::AutoLock auto_lock(thiz->lock_);
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    thiz->latency_ = latency;
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32_t buffer_size =
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        thiz->sample_count_ * thiz->channel_count_ * sizeof(int16_t);
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PP_DCHECK(num_bytes <= buffer_size);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PP_DCHECK(num_bytes % (thiz->channel_count_ * sizeof(int16_t)) == 0);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    memcpy(thiz->samples_, samples, num_bytes);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    memset(reinterpret_cast<char*>(thiz->samples_) + num_bytes, 0,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           buffer_size - num_bytes);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void MonitorDeviceChangeCallback(void* user_data,
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          uint32_t device_count,
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const PP_Resource devices[]) {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MyInstance* thiz = static_cast<MyInstance*>(user_data);
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string device_names = "Monitor:";
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thiz->monitor_devices_.clear();
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thiz->monitor_devices_.reserve(device_count);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t index = 0; index < device_count; ++index) {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      thiz->monitor_devices_.push_back(pp::DeviceRef_Dev(devices[index]));
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pp::Var name = thiz->monitor_devices_.back().GetName();
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PP_DCHECK(name.is_string());
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (index != 0)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        device_names += kDelimiter;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      device_names += name.AsString();
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    thiz->PostMessage(pp::Var(device_names));
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::CompletionCallbackFactory<MyInstance> callback_factory_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t sample_count_;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t channel_count_;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int16_t* samples_;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PP_TimeDelta latency_;
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32_t timer_interval_;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Painting stuff.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Size size_;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D device_context_;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pending_paint_;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool waiting_for_flush_completion_;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // There is no need to have two resources to do capturing and device detecting
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // separately. However, this makes the code of monitoring device change
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // easier.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::AudioInput_Dev audio_input_;
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pp::AudioInput_Dev device_detector_;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<pp::DeviceRef_Dev> enumerate_devices_;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<pp::DeviceRef_Dev> monitor_devices_;
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Protects |samples_| and |latency_|.
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  pp::Lock lock_;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MyModule : public pp::Module {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new MyInstance(instance);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace pp {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory function for your specialization of the Module object.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Module* CreateModule() {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new MyModule();
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace pp
351