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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
// Copyright (c) 2012 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.
#ifndef MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_
#define MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>
#include "base/compiler_specific.h"
#include "base/synchronization/lock.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_fifo.h"
namespace media {
class AudioManagerMac;
class ChannelMixer;
// AudioSynchronizedStream allows arbitrary combinations of input and output
// devices running off different clocks and using different drivers, with
// potentially differing sample-rates. It implements AudioOutputStream
// and shuttles its synchronized I/O data using AudioSourceCallback.
//
// It is required to first acquire the native sample rate of the selected
// output device and then use the same rate when creating this object.
//
// ............................................................................
// Theory of Operation:
// .
// INPUT THREAD . OUTPUT THREAD
// +-----------------+ +------+ .
// | Input AudioUnit | --> | | .
// +-----------------+ | | .
// | FIFO | .
// | | +-----------+
// | | -----> | Varispeed |
// | | +-----------+
// +------+ . |
// . | +-----------+
// . OnMoreIOData() --> | Output AU |
// . +-----------+
//
// The input AudioUnit's InputProc is called on one thread which feeds the
// FIFO. The output AudioUnit's OutputProc is called on a second thread
// which pulls on the varispeed to get the current input data. The varispeed
// handles mismatches between input and output sample-rate and also clock drift
// between the input and output drivers. The varispeed consumes its data from
// the FIFO and adjusts its rate dynamically according to the amount
// of data buffered in the FIFO. If the FIFO starts getting too much data
// buffered then the varispeed will speed up slightly to compensate
// and similarly if the FIFO doesn't have enough data buffered then the
// varispeed will slow down slightly.
//
// Finally, once the input data is available then OnMoreIOData() is called
// which is given this input, and renders the output which is finally sent
// to the Output AudioUnit.
class AudioSynchronizedStream : public AudioOutputStream {
public:
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
AudioSynchronizedStream(AudioManagerMac* manager,
const AudioParameters& params,
AudioDeviceID input_id,
AudioDeviceID output_id);
virtual ~AudioSynchronizedStream();
// Implementation of AudioOutputStream.
virtual bool Open() OVERRIDE;
virtual void Close() OVERRIDE;
virtual void Start(AudioSourceCallback* callback) OVERRIDE;
virtual void Stop() OVERRIDE;
virtual void SetVolume(double volume) OVERRIDE;
virtual void GetVolume(double* volume) OVERRIDE;
OSStatus SetInputDeviceAsCurrent(AudioDeviceID input_id);
OSStatus SetOutputDeviceAsCurrent(AudioDeviceID output_id);
AudioDeviceID GetInputDeviceID() { return input_info_.id_; }
AudioDeviceID GetOutputDeviceID() { return output_info_.id_; }
bool IsRunning();
private:
// Initialization.
OSStatus CreateAudioUnits();
OSStatus SetupInput(AudioDeviceID input_id);
OSStatus EnableIO();
OSStatus SetupOutput(AudioDeviceID output_id);
OSStatus SetupCallbacks();
OSStatus SetupStreamFormats();
void AllocateInputData();
// Handlers for the AudioUnit callbacks.
OSStatus HandleInputCallback(AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
OSStatus HandleVarispeedCallback(AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
OSStatus HandleOutputCallback(AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
// AudioUnit callbacks.
static OSStatus InputProc(void* user_data,
AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
static OSStatus VarispeedProc(void* user_data,
AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
static OSStatus OutputProc(void* user_data,
AudioUnitRenderActionFlags* io_action_flags,
const AudioTimeStamp* time_stamp,
UInt32 bus_number,
UInt32 number_of_frames,
AudioBufferList* io_data);
// Our creator.
AudioManagerMac* manager_;
// Client parameters.
AudioParameters params_;
double input_sample_rate_;
double output_sample_rate_;
// Pointer to the object that will provide the audio samples.
AudioSourceCallback* source_;
// Values used in Open().
AudioDeviceID input_id_;
AudioDeviceID output_id_;
// The input AudioUnit renders its data here.
AudioBufferList* input_buffer_list_;
// Holds the actual data for |input_buffer_list_|.
scoped_ptr<AudioBus> input_bus_;
// Used to overlay AudioBufferLists.
scoped_ptr<AudioBus> wrapper_bus_;
class AudioDeviceInfo {
public:
AudioDeviceInfo()
: id_(kAudioDeviceUnknown),
is_input_(false),
buffer_size_frames_(0) {}
void Initialize(AudioDeviceID inID, bool isInput);
bool IsInitialized() const { return id_ != kAudioDeviceUnknown; }
AudioDeviceID id_;
bool is_input_;
UInt32 buffer_size_frames_;
};
AudioDeviceInfo input_info_;
AudioDeviceInfo output_info_;
// Used for input to output buffering.
AudioFifo fifo_;
// The optimal number of frames we'd like to keep in the FIFO at all times.
int target_fifo_frames_;
// A running average of the measured delta between actual number of frames
// in the FIFO versus |target_fifo_frames_|.
double average_delta_;
// A varispeed rate scalar which is calculated based on FIFO drift.
double fifo_rate_compensation_;
// AudioUnits.
AudioUnit input_unit_;
AudioUnit varispeed_unit_;
AudioUnit output_unit_;
double first_input_time_;
bool is_running_;
int hardware_buffer_size_;
int channels_;
// Channel mixer used to transform mono to stereo data. It is only created
// if the input_hardware_channels is mono.
scoped_ptr<ChannelMixer> channel_mixer_;
scoped_ptr<AudioBus> mixer_bus_;
DISALLOW_COPY_AND_ASSIGN(AudioSynchronizedStream);
};
} // namespace media
#endif // MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_
|