summaryrefslogtreecommitdiffstats
path: root/media/audio/simple_sources.cc
blob: 1edd2b240188af827967464e0eb5545683f8403c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2010 The Chromium 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 "media/audio/simple_sources.h"

#include <algorithm>
#include <math.h>

#include "base/basictypes.h"
#include "base/logging.h"
#include "media/audio/audio_output.h"

//////////////////////////////////////////////////////////////////////////////
// SineWaveAudioSource implementation.

SineWaveAudioSource::SineWaveAudioSource(Format format, int channels,
                                         double freq, double sample_freq)
    : format_(format),
      channels_(channels),
      freq_(freq),
      sample_freq_(sample_freq) {
  // TODO(cpu): support other formats.
  DCHECK((format_ == FORMAT_16BIT_LINEAR_PCM) && (channels_ == 1));
}

// The implementation could be more efficient if a lookup table is constructed
// but it is efficient enough for our simple needs.
uint32 SineWaveAudioSource::OnMoreData(AudioOutputStream* stream, void* dest,
                                       uint32 max_size, uint32 pending_bytes) {
  const double kTwoPi = 2.0 * 3.141592653589;
  double f = freq_ / sample_freq_;
  int16* sin_tbl = reinterpret_cast<int16*>(dest);
  uint32 len = max_size / sizeof(int16);
  // The table is filled with s(t) = 32768*sin(2PI*f*t).
  for (uint32 ix = 0; ix != len; ++ix) {
    double th = kTwoPi * ix * f;
    sin_tbl[ix] = static_cast<int16>((1 << 15) * sin(th));
  }
  return max_size;
}

void SineWaveAudioSource::OnClose(AudioOutputStream* stream) {
}

void SineWaveAudioSource::OnError(AudioOutputStream* stream, int code) {
  NOTREACHED();
}

//////////////////////////////////////////////////////////////////////////////
// PushSource implementation.

PushSource::PushSource()
    : buffered_bytes_(0),
      front_buffer_consumed_(0) {
}

PushSource::~PushSource() {
  CleanUp();
}

uint32 PushSource::OnMoreData(AudioOutputStream* stream, void* dest,
                              uint32 max_size, uint32 pending_bytes) {
  uint32 copied = 0;
  while (copied < max_size) {
    AutoLock auto_lock(lock_);

    // Under lock processing in this scope.
    if (!packets_.size())
      break;
    Packet packet = packets_.front();
    uint32 size = std::min(max_size - copied,
                           packet.size - front_buffer_consumed_);
    memcpy(static_cast<char*>(dest) + copied,
           packet.buffer + front_buffer_consumed_,
           size);
    front_buffer_consumed_ += size;
    buffered_bytes_ -= size;
    copied += size;
    if (front_buffer_consumed_ == packet.size) {
      delete [] packet.buffer;
      packets_.pop_front();
      front_buffer_consumed_ = 0;
    }
  }
  return copied;
}

void PushSource::OnClose(AudioOutputStream* stream) {
  CleanUp();
}

void PushSource::OnError(AudioOutputStream* stream, int code) {
  NOTREACHED();
}

// TODO(cpu): Manage arbitrary large sizes.
bool PushSource::Write(const void *data, uint32 len) {
  if (len == 0) {
    NOTREACHED();
    return false;
  }
  Packet packet = { new char[len], len };
  memcpy(packet.buffer, data, packet.size);
  // Under lock processing here.
  AutoLock auto_lock(lock_);
  packets_.push_back(packet);
  buffered_bytes_ += len;
  return true;
}

uint32 PushSource::UnProcessedBytes() {
  AutoLock auto_lock(lock_);
  return buffered_bytes_;
}

void PushSource::ClearAll() {
  // Cleanup() will discard all the data.
  CleanUp();
}

void PushSource::CleanUp() {
  AutoLock auto_lock(lock_);
  PacketList::const_iterator it;
  for (it = packets_.begin(); it != packets_.end(); ++it) {
    delete [] it->buffer;
  }
  packets_.clear();
  buffered_bytes_ = 0;
  front_buffer_consumed_ = 0;
}