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