1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Implementation notes:
6//
7// - It is recommended to first acquire the native sample rate of the default
8//   output device and then use the same rate when creating this object.
9//   Use AudioManagerMac::HardwareSampleRate() to retrieve the sample rate.
10// - Calling Close() also leads to self destruction.
11// - The latency consists of two parts:
12//   1) Hardware latency, which includes Audio Unit latency, audio device
13//      latency;
14//   2) The delay between the moment getting the callback and the scheduled time
15//      stamp that tells when the data is going to be played out.
16//
17#ifndef MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_
18#define MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_
19
20#include <AudioUnit/AudioUnit.h>
21#include <CoreAudio/CoreAudio.h>
22
23#include "base/compiler_specific.h"
24#include "base/synchronization/lock.h"
25#include "media/audio/audio_io.h"
26#include "media/audio/audio_parameters.h"
27
28namespace media {
29
30class AudioManagerMac;
31
32// Implementation of AudioOuputStream for Mac OS X using the
33// AUHAL Audio Unit present in OS 10.4 and later.
34// It is useful for low-latency output with optional synchronized
35// input.
36//
37// Overview of operation:
38// 1) An object of AUHALStream is created by the AudioManager
39// factory: audio_man->MakeAudioStream().
40// 2) Next some thread will call Open(), at that point the underlying
41// AUHAL Audio Unit is created and configured to use the |device|.
42// 3) Then some thread will call Start(source).
43// Then the AUHAL is started which creates its own thread which
44// periodically will call the source for more data as buffers are being
45// consumed.
46// 4) At some point some thread will call Stop(), which we handle by directly
47// stopping the default output Audio Unit.
48// 6) The same thread that called stop will call Close() where we cleanup
49// and notify the audio manager, which likely will destroy this object.
50
51class AUHALStream : public AudioOutputStream {
52 public:
53  // |manager| creates this object.
54  // |device| is the CoreAudio device to use for the stream.
55  // It will often be the default output device.
56  AUHALStream(AudioManagerMac* manager,
57              const AudioParameters& params,
58              AudioDeviceID device);
59  // The dtor is typically called by the AudioManager only and it is usually
60  // triggered by calling AudioOutputStream::Close().
61  virtual ~AUHALStream();
62
63  // Implementation of AudioOutputStream.
64  virtual bool Open() OVERRIDE;
65  virtual void Close() OVERRIDE;
66  virtual void Start(AudioSourceCallback* callback) OVERRIDE;
67  virtual void Stop() OVERRIDE;
68  virtual void SetVolume(double volume) OVERRIDE;
69  virtual void GetVolume(double* volume) OVERRIDE;
70
71 private:
72  // AUHAL callback.
73  static OSStatus InputProc(void* user_data,
74                            AudioUnitRenderActionFlags* flags,
75                            const AudioTimeStamp* time_stamp,
76                            UInt32 bus_number,
77                            UInt32 number_of_frames,
78                            AudioBufferList* io_data);
79
80  OSStatus Render(AudioUnitRenderActionFlags* flags,
81                  const AudioTimeStamp* output_time_stamp,
82                  UInt32 bus_number,
83                  UInt32 number_of_frames,
84                  AudioBufferList* io_data);
85
86  // Helper method to enable input and output.
87  bool EnableIO(bool enable, UInt32 scope);
88
89  // Sets the stream format on the AUHAL to PCM Float32 non-interleaved
90  // for the given number of channels on the given scope and element.
91  // The created stream description will be stored in |desc|.
92  bool SetStreamFormat(AudioStreamBasicDescription* desc,
93                       int channels,
94                       UInt32 scope,
95                       UInt32 element);
96
97  // Creates the AUHAL, sets its stream format, buffer-size, etc.
98  bool ConfigureAUHAL();
99
100  // Creates the input and output busses.
101  void CreateIOBusses();
102
103  // Gets the fixed playout device hardware latency and stores it. Returns 0
104  // if not available.
105  double GetHardwareLatency();
106
107  // Gets the current playout latency value.
108  double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp);
109
110  // Our creator, the audio manager needs to be notified when we close.
111  AudioManagerMac* manager_;
112
113  AudioParameters params_;
114  // For convenience - same as in params_.
115  int input_channels_;
116  int output_channels_;
117
118  // Buffer-size.
119  size_t number_of_frames_;
120
121  // Pointer to the object that will provide the audio samples.
122  AudioSourceCallback* source_;
123
124  // Protects |source_|.  Necessary since Render() calls seem to be in flight
125  // when |audio_unit_| is supposedly stopped.  See http://crbug.com/178765.
126  base::Lock source_lock_;
127
128  // Holds the stream format details such as bitrate.
129  AudioStreamBasicDescription input_format_;
130  AudioStreamBasicDescription output_format_;
131
132  // The audio device to use with the AUHAL.
133  // We can potentially handle both input and output with this device.
134  AudioDeviceID device_;
135
136  // The AUHAL Audio Unit which talks to |device_|.
137  AudioUnit audio_unit_;
138
139  // Volume level from 0 to 1.
140  float volume_;
141
142  // Fixed playout hardware latency in frames.
143  double hardware_latency_frames_;
144
145  // The flag used to stop the streaming.
146  bool stopped_;
147
148  // The flag used to indicate if the AudioManager has been notified of a
149  // potential device change.  Reset to false during Start().
150  bool notified_for_possible_device_change_;
151
152  // The input AudioUnit renders its data here.
153  scoped_ptr<uint8[]> input_buffer_list_storage_;
154  AudioBufferList* input_buffer_list_;
155
156  // Holds the actual data for |input_buffer_list_|.
157  scoped_ptr<AudioBus> input_bus_;
158
159  // Container for retrieving data from AudioSourceCallback::OnMoreIOData().
160  scoped_ptr<AudioBus> output_bus_;
161
162  DISALLOW_COPY_AND_ASSIGN(AUHALStream);
163};
164
165}  // namespace media
166
167#endif  // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_
168