Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Unified Diff: experimental/life2011/life_stage_5/web_wav_sound_resource.cc

Issue 6801054: Adding class WebWavSoundResource, downloads and decode wav audio data from a URL. Implements the (Closed) Base URL: http://naclports.googlecode.com/svn/trunk/src/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « experimental/life2011/life_stage_5/web_wav_sound_resource.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: experimental/life2011/life_stage_5/web_wav_sound_resource.cc
===================================================================
--- experimental/life2011/life_stage_5/web_wav_sound_resource.cc (revision 0)
+++ experimental/life2011/life_stage_5/web_wav_sound_resource.cc (revision 0)
@@ -0,0 +1,204 @@
+// Copyright 2011 The Native Client 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 "web_wav_sound_resource.h"
+#include "web_resource_loader_inl.h"
+
+#include <ppapi/cpp/instance.h>
+#include <ppapi/cpp/url_response_info.h>
+#include <ppapi/cpp/var.h>
+
+#include <algorithm>
+#include <string.h>
+
+namespace {
+// Wav record descriptor per
+// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+#pragma pack(push, 1)
+struct WavRecord {
+ // Header.
+ char header_id[4]; // Should be "RIFF"
+ int32_t record_size; // Should be size of data minus 8
+ char format[4]; // Should be "WAVE"
+ // Subchunk 1, i.e. format descriptor.
+ char format_chunk_id[4]; // Should be "fmt ".
+ int32_t format_chunk_size; // Should be 16.
+ int16_t audio_format; // Should be 1 for uncompressed audio.
+ int16_t num_channels; // 1 for mono, 2 for stereo.
+ int32_t sample_rate;
+ int32_t byte_rate;
+ int16_t block_align;
+ int16_t bits_per_sample;
+ // Data chunk.
+ char data_id[4]; // Should be "data"
+ int32_t audio_chunk_size; // Size of sample data that follows.
+ char audio_data; // The first byte of actual sound data;
+};
+#pragma pack(pop)
+
+// Parse the headers in the url response and return the length of the
+// resource content ion bytes. Returns 0 in case of error.
+// TODO(gwink): Define a wrapper class around URLResponseInfo and parse
+// the headers into a map that can be conveniently queried.
+int GetContentLength(const pp::URLResponseInfo response) {
+ pp::Var header_var = response.GetHeaders();
+ if (!header_var.is_string()) {
+ return 0;
+ }
+
+ static const std::string kContentLengthKey("Content-Length: ");
+ std::string headers = header_var.AsString();
+ size_t i = headers.find(kContentLengthKey);
+ if (i == headers.npos) {
+ return 0;
+ }
+
+ return atoi(headers.substr(i + kContentLengthKey.length()).c_str());
+}
+
+// Verify that the wav data in the buffer is valid and playable with
+// the pepper audio interface.
+bool VerifyWavData(const char* data, size_t data_size) {
+ // Do we have enough data.
+ printf("Wav data size: %i\n", (int)data_size);
+ if (data_size < sizeof(WavRecord)) {
+ return false;
+ }
+
+ const WavRecord* wav = reinterpret_cast<const WavRecord*>(data);
+ // Check various chunk formats.
+ printf("Wav header id: |%4.4s|\n", wav->header_id);
+ printf("Wav audio format id: |%4.4s|\n", wav->format);
+ printf("Wav format header id: |%4.4s|\n", wav->format_chunk_id);
+ printf("Wav data header id: |%4.4s|\n", wav->data_id);
+ if (::strncmp(wav->header_id, "RIFF", 4) != 0 ||
+ ::strncmp(wav->format, "WAVE", 4) != 0 ||
+ ::strncmp(wav->format_chunk_id, "fmt ", 4) != 0 ||
+ ::strncmp(wav->data_id, "data", 4) != 0) {
+ printf(" ** bad format id.\n");
+ return false;
+ }
+ // Check that we support the audio format.
+ printf("Wav sample rate: %i\n", (int)wav->sample_rate);
+ if (wav->sample_rate != 44100 && wav->sample_rate != 48000) {
+ printf(" ** bad sample rate.\n");
+ return false;
+ }
+ printf("Wav num channels: %i\n", wav->num_channels);
+ printf("Wav bits per sample: %i\n", wav->bits_per_sample);
+ if (wav->num_channels != 2 || wav->bits_per_sample != 16) {
+ printf(" ** not stereo or not 16-bit.\n");
+ return false;
+ }
+ // Finally, check that the actual data size and wav sample data size match.
+ printf("Wav audio size: actual = %i, expected = %i\n",
+ (int)wav->audio_chunk_size,
+ static_cast<int>(data_size - sizeof(WavRecord) + 1));
+ return (wav->audio_chunk_size ==
+ static_cast<int32_t>(data_size - sizeof(WavRecord) + 1));
+}
+
+} // anonymous namespace
+
+
+namespace life {
+
+WebWavSoundResource::WebWavSoundResource()
+ : is_ready_(false),
+ wav_data_size_(0),
+ received_data_size_(0),
+ loader_(NULL) {
+}
+
+WebWavSoundResource::~WebWavSoundResource() {
+ Clear();
+}
+
+void WebWavSoundResource::Init(const std::string& url, pp::Instance* instance) {
+ assert(wav_data_.empty()); // Can only init once.
+ if (wav_data_.empty()) {
+ loader_ = new Loader(instance, this);
+ loader_->LoadURL(url);
+ }
+}
+
+int32_t WebWavSoundResource::GetSampleRate() const {
+ assert(IsReady());
+ const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
+ return wav->sample_rate;
+}
+
+const char* WebWavSoundResource::GetAudioData() const {
+ assert(IsReady());
+ const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
+ return &(wav->audio_data);
+}
+
+size_t WebWavSoundResource::GetAudioDataSize() const {
+ assert(IsReady());
+ const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
+ return wav->audio_chunk_size;
+}
+
+bool WebWavSoundResource::OnWebResourceLoaderCallback(
+ Loader::DispatchOpCode op_code, Loader* loader) {
+ switch(op_code) {
+ case Loader::kUrlResponseInfoReady: {
+ int content_length = GetContentLength(loader->GetResponseInfo());
+ if (content_length <= 0) {
+ // Either the download failed, or the sound data is bad. Abort.
+ Clear();
+ return false;
+ } else {
+ // Create a local buffer big enough to receive the sound data.
+ wav_data_.reserve(content_length);
+ wav_data_size_ = content_length;
+ received_data_size_ = 0;
+ return true;
+ }
+ break;
+ }
+ case Loader::kDataReceived: {
+ if (received_data_size_ + loader->data_size() > wav_data_size_) {
+ // Size of sound data exceeds expected size. Abort.
+ return false;
+ } else {
+ // Append chunk of data to local sound buffer.
+ ::memcpy(&wav_data_[0] + received_data_size_,
+ loader->buffer(), loader->data_size());
+ received_data_size_ += loader->data_size();
+ return true;
+ }
+ break;
+ }
+ case Loader::kDownloadComplete: {
+ is_ready_ = VerifyWavData(&wav_data_[0], wav_data_size_);
+ if (!is_ready_) {
+ Clear();
+ }
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+void WebWavSoundResource::OnWebResourceLoaderError(int32_t error,
+ Loader* loader) {
+}
+
+void WebWavSoundResource::OnWebResourceLoaderDone(Loader* loader) {
+ loader_->CloseAndDeleteSelf();
+ loader_ = NULL;
+}
+
+void WebWavSoundResource::Clear() {
+ is_ready_ = false;
+ wav_data_.clear();
+ wav_data_size_ = 0;
+ received_data_size_ = 0;
+ loader_->CloseAndDeleteSelf();
bbudge-google 2011/04/08 17:08:29 This needs a NULL check. Someone could instantiate
+ loader_ = NULL;
+}
+
+} // namespace life
« no previous file with comments | « experimental/life2011/life_stage_5/web_wav_sound_resource.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698