summaryrefslogtreecommitdiff
path: root/chromium/media/audio/mac/audio_auhal_mac.h
blob: 66feb8d0d11f43358626b5d657e2a51b4edcd00f (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
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
// Copyright 2013 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.
//
// Implementation notes:
//
// - It is recommended to first acquire the native sample rate of the default
//   output device and then use the same rate when creating this object.
//   Use AudioManagerMac::HardwareSampleRate() to retrieve the sample rate.
// - Calling Close() also leads to self destruction.
// - The latency consists of two parts:
//   1) Hardware latency, which includes Audio Unit latency, audio device
//      latency;
//   2) The delay between the moment getting the callback and the scheduled time
//      stamp that tells when the data is going to be played out.
//
#ifndef MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_
#define MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_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"

namespace media {

class AudioManagerMac;

// Implementation of AudioOuputStream for Mac OS X using the
// AUHAL Audio Unit present in OS 10.4 and later.
// It is useful for low-latency output with optional synchronized
// input.
//
// Overview of operation:
// 1) An object of AUHALStream is created by the AudioManager
// factory: audio_man->MakeAudioStream().
// 2) Next some thread will call Open(), at that point the underlying
// AUHAL Audio Unit is created and configured to use the |device|.
// 3) Then some thread will call Start(source).
// Then the AUHAL is started which creates its own thread which
// periodically will call the source for more data as buffers are being
// consumed.
// 4) At some point some thread will call Stop(), which we handle by directly
// stopping the default output Audio Unit.
// 6) The same thread that called stop will call Close() where we cleanup
// and notify the audio manager, which likely will destroy this object.

class AUHALStream : public AudioOutputStream {
 public:
  // |manager| creates this object.
  // |device| is the CoreAudio device to use for the stream.
  // It will often be the default output device.
  AUHALStream(AudioManagerMac* manager,
              const AudioParameters& params,
              AudioDeviceID device);
  // The dtor is typically called by the AudioManager only and it is usually
  // triggered by calling AudioOutputStream::Close().
  virtual ~AUHALStream();

  // 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;

 private:
  // AUHAL callback.
  static OSStatus InputProc(void* user_data,
                            AudioUnitRenderActionFlags* flags,
                            const AudioTimeStamp* time_stamp,
                            UInt32 bus_number,
                            UInt32 number_of_frames,
                            AudioBufferList* io_data);

  OSStatus Render(AudioUnitRenderActionFlags* flags,
                  const AudioTimeStamp* output_time_stamp,
                  UInt32 bus_number,
                  UInt32 number_of_frames,
                  AudioBufferList* io_data);

  // Helper method to enable input and output.
  bool EnableIO(bool enable, UInt32 scope);

  // Sets the stream format on the AUHAL to PCM Float32 non-interleaved
  // for the given number of channels on the given scope and element.
  // The created stream description will be stored in |desc|.
  bool SetStreamFormat(AudioStreamBasicDescription* desc,
                       int channels,
                       UInt32 scope,
                       UInt32 element);

  // Creates the AUHAL, sets its stream format, buffer-size, etc.
  bool ConfigureAUHAL();

  // Creates the input and output busses.
  void CreateIOBusses();

  // Gets the fixed playout device hardware latency and stores it. Returns 0
  // if not available.
  double GetHardwareLatency();

  // Gets the current playout latency value.
  double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp);

  // Our creator, the audio manager needs to be notified when we close.
  AudioManagerMac* manager_;

  AudioParameters params_;
  // For convenience - same as in params_.
  int input_channels_;
  int output_channels_;

  // Buffer-size.
  size_t number_of_frames_;

  // Pointer to the object that will provide the audio samples.
  AudioSourceCallback* source_;

  // Protects |source_|.  Necessary since Render() calls seem to be in flight
  // when |audio_unit_| is supposedly stopped.  See http://crbug.com/178765.
  base::Lock source_lock_;

  // Holds the stream format details such as bitrate.
  AudioStreamBasicDescription input_format_;
  AudioStreamBasicDescription output_format_;

  // The audio device to use with the AUHAL.
  // We can potentially handle both input and output with this device.
  AudioDeviceID device_;

  // The AUHAL Audio Unit which talks to |device_|.
  AudioUnit audio_unit_;

  // Volume level from 0 to 1.
  float volume_;

  // Fixed playout hardware latency in frames.
  double hardware_latency_frames_;

  // The flag used to stop the streaming.
  bool stopped_;

  // The flag used to indicate if the AudioManager has been notified of a
  // potential device change.  Reset to false during Start().
  bool notified_for_possible_device_change_;

  // The input AudioUnit renders its data here.
  scoped_ptr<uint8[]> input_buffer_list_storage_;
  AudioBufferList* input_buffer_list_;

  // Holds the actual data for |input_buffer_list_|.
  scoped_ptr<AudioBus> input_bus_;

  // Container for retrieving data from AudioSourceCallback::OnMoreIOData().
  scoped_ptr<AudioBus> output_bus_;

  DISALLOW_COPY_AND_ASSIGN(AUHALStream);
};

}  // namespace media

#endif  // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_