1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/audio_buffer_queue.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/audio_bus.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/buffers.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace media {
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochAudioBufferQueue::AudioBufferQueue() { Clear(); }
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochAudioBufferQueue::~AudioBufferQueue() {}
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::Clear() {
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  buffers_.clear();
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  current_buffer_ = buffers_.begin();
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  current_buffer_offset_ = 0;
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  frames_ = 0;
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Add the buffer to the queue. Inserting into deque invalidates all
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // iterators, so point to the first buffer.
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  buffers_.push_back(buffer_in);
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  current_buffer_ = buffers_.begin();
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Update the |frames_| counter since we have added frames.
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  frames_ += buffer_in->frame_count();
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_GT(frames_, 0);  // make sure it doesn't overflow.
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint AudioBufferQueue::ReadFrames(int frames,
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 int dest_frame_offset,
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 AudioBus* dest) {
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GE(dest->frames(), frames + dest_frame_offset);
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return InternalRead(frames, true, 0, dest_frame_offset, dest);
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint AudioBufferQueue::PeekFrames(int frames,
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 int source_frame_offset,
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 int dest_frame_offset,
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 AudioBus* dest) {
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_GE(dest->frames(), frames);
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return InternalRead(
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      frames, false, source_frame_offset, dest_frame_offset, dest);
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::SeekFrames(int frames) {
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Perform seek only if we have enough bytes in the queue.
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_LE(frames, frames_);
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int taken = InternalRead(frames, true, 0, 0, NULL);
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_EQ(taken, frames);
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint AudioBufferQueue::InternalRead(int frames,
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   bool advance_position,
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                   int source_frame_offset,
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                   int dest_frame_offset,
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   AudioBus* dest) {
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Counts how many frames are actually read from the buffer queue.
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int taken = 0;
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BufferQueue::iterator current_buffer = current_buffer_;
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int current_buffer_offset = current_buffer_offset_;
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int frames_to_skip = source_frame_offset;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  while (taken < frames) {
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // |current_buffer| is valid since the first time this buffer is appended
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // with data. Make sure there is data to be processed.
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (current_buffer == buffers_.end())
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_refptr<AudioBuffer> buffer = *current_buffer;
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int remaining_frames_in_buffer =
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        buffer->frame_count() - current_buffer_offset;
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (frames_to_skip > 0) {
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // If there are frames to skip, do it first. May need to skip into
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // subsequent buffers.
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_buffer_offset += skipped;
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      frames_to_skip -= skipped;
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else {
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Find the right amount to copy from the current buffer. We shall copy no
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // more than |frames| frames in total and each single step copies no more
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // than the current buffer size.
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int copied = std::min(frames - taken, remaining_frames_in_buffer);
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // if |dest| is NULL, there's no need to copy.
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (dest) {
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        buffer->ReadFrames(
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            copied, current_buffer_offset, dest_frame_offset + taken, dest);
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Increase total number of frames copied, which regulates when to end
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // this loop.
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      taken += copied;
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // We have read |copied| frames from the current buffer. Advance the
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // offset.
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_buffer_offset += copied;
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Has the buffer has been consumed?
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (current_buffer_offset == buffer->frame_count()) {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // If we are at the last buffer, no more data to be copied, so stop.
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      BufferQueue::iterator next = current_buffer + 1;
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (next == buffers_.end())
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        break;
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Advances the iterator.
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_buffer = next;
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      current_buffer_offset = 0;
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (advance_position) {
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Update the appropriate values since |taken| frames have been copied out.
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    frames_ -= taken;
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK_GE(frames_, 0);
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(current_buffer_ != buffers_.end() || frames_ == 0);
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Remove any buffers before the current buffer as there is no going
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // backwards.
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    buffers_.erase(buffers_.begin(), current_buffer);
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    current_buffer_ = buffers_.begin();
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    current_buffer_offset_ = current_buffer_offset;
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return taken;
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace media
138