10f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
20f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
30f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// found in the LICENSE file.
40f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
50f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "media/audio/sounds/wav_audio_handler.h"
60f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
70f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include <algorithm>
80f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include <cstring>
90f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/logging.h"
110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/sys_byteorder.h"
120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "media/base/audio_bus.h"
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace {
150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kChunkId[] = "RIFF";
170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kFormat[] = "WAVE";
180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kSubchunk1Id[] = "fmt ";
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kSubchunk2Id[] = "data";
200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// The size of the header of a wav file. The header consists of 'RIFF', 4 bytes
220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// of total data length, and 'WAVE'.
230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kWavFileHeaderSize = 12;
240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// The size of a chunk header in wav file format. A chunk header consists of a
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// tag ('fmt ' or 'data') and 4 bytes of chunk length.
270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kChunkHeaderSize = 8;
280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// The minimum size of 'fmt' chunk.
300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kFmtChunkMinimumSize = 16;
310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// The offsets of 'fmt' fields.
330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kAudioFormatOffset = 0;
340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kChannelOffset = 2;
350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kSampleRateOffset = 4;
360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const size_t kBitsPerSampleOffset = 14;
370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Some constants for audio format.
390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const int kAudioFormatPCM = 1;
400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Reads an integer from |data| with |offset|.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template <typename T>
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)T ReadInt(const base::StringPiece& data, size_t offset) {
440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  CHECK_LE(offset + sizeof(T), data.size());
450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  T result;
460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  memcpy(&result, data.data() + offset, sizeof(T));
470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#if !defined(ARCH_CPU_LITTLE_ENDIAN)
480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  result = base::ByteSwap(result);
490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#endif
500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return result;
510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace
540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace media {
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)WavAudioHandler::WavAudioHandler(const base::StringPiece& wav_data)
580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    : num_channels_(0),
590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      sample_rate_(0),
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      bits_per_sample_(0) {
610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  CHECK_LE(kWavFileHeaderSize, wav_data.size()) << "wav data is too small";
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  CHECK(wav_data.starts_with(kChunkId) &&
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        memcmp(wav_data.data() + 8, kFormat, 4) == 0)
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      << "incorrect wav header";
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  uint32 total_length = std::min(ReadInt<uint32>(wav_data, 4),
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                 static_cast<uint32>(wav_data.size()));
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  uint32 offset = kWavFileHeaderSize;
690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  while (offset < total_length) {
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const int length = ParseSubChunk(wav_data.substr(offset));
710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CHECK_LE(0, length) << "can't parse wav sub-chunk";
720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    offset += length;
730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int frame_count = data_.size() * 8 / num_channels_ / bits_per_sample_;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  params_ = AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            GuessChannelLayout(num_channels_),
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            sample_rate_,
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            bits_per_sample_,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            frame_count);
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)WavAudioHandler::~WavAudioHandler() {}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool WavAudioHandler::AtEnd(size_t cursor) const {
860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return data_.size() <= cursor;
870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool WavAudioHandler::CopyTo(AudioBus* bus,
900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             size_t cursor,
910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             size_t* bytes_written) const {
920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!bus)
930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (bus->channels() != params_.channels()) {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Number of channel mismatch.";
960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (AtEnd(cursor)) {
990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    bus->Zero();
1000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return true;
1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int remaining_frames =
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (data_.size() - cursor) / params_.GetBytesPerFrame();
1040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const int frames = std::min(bus->frames(), remaining_frames);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bus->FromInterleaved(data_.data() + cursor, frames,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       params_.bits_per_sample() / 8);
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *bytes_written = frames * params_.GetBytesPerFrame();
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bus->ZeroFramesPartial(frames, bus->frames() - frames);
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)int WavAudioHandler::ParseSubChunk(const base::StringPiece& data) {
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (data.size() < kChunkHeaderSize)
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return data.size();
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  uint32 chunk_length = ReadInt<uint32>(data, 4);
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (data.starts_with(kSubchunk1Id)) {
1170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!ParseFmtChunk(data.substr(kChunkHeaderSize, chunk_length)))
1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return -1;
1190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else if (data.starts_with(kSubchunk2Id)) {
1200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!ParseDataChunk(data.substr(kChunkHeaderSize, chunk_length)))
1210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return -1;
1220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Unknown data chunk: " << data.substr(0, 4) << ".";
1240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return chunk_length + kChunkHeaderSize;
1260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool WavAudioHandler::ParseFmtChunk(const base::StringPiece& data) {
1290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (data.size() < kFmtChunkMinimumSize) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DLOG(ERROR) << "Data size " << data.size() << " is too short.";
1310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
1320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK_EQ(ReadInt<uint16>(data, kAudioFormatOffset), kAudioFormatPCM);
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  num_channels_ = ReadInt<uint16>(data, kChannelOffset);
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  sample_rate_ = ReadInt<uint32>(data, kSampleRateOffset);
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bits_per_sample_ = ReadInt<uint16>(data, kBitsPerSampleOffset);
1370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
1380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool WavAudioHandler::ParseDataChunk(const base::StringPiece& data) {
1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  data_ = data;
1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace media
146