summaryrefslogtreecommitdiffstats
path: root/media/audio/mac/audio_manager_mac.cc
blob: 48df6ab154633cd0829282898c3ded59e04d1594 (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
// 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 <CoreAudio/AudioHardware.h>

#include "base/sys_info.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/mac/audio_input_mac.h"
#include "media/audio/mac/audio_manager_mac.h"
#include "media/audio/mac/audio_output_mac.h"
#include "media/base/limits.h"

namespace {

const int kMaxInputChannels = 2;

// Maximum number of output streams that can be open simultaneously.
const size_t kMaxOutputStreams = 50;

// By experiment the maximum number of audio streams allowed in Leopard
// is 18. But we put a slightly smaller number just to be safe.
const size_t kMaxOutputStreamsLeopard = 15;

// Initialized to ether |kMaxOutputStreams| or |kMaxOutputStreamsLeopard|.
size_t g_max_output_streams = 0;

// Returns the number of audio streams allowed. This is a practical limit to
// prevent failure caused by too many audio streams opened.
size_t GetMaxAudioOutputStreamsAllowed() {
  if (g_max_output_streams == 0) {
    // We are hitting a bug in Leopard where too many audio streams will cause
    // a deadlock in the AudioQueue API when starting the stream. Unfortunately
    // there's no way to detect it within the AudioQueue API, so we put a
    // special hard limit only for Leopard.
    // See bug: http://crbug.com/30242
    int32 major, minor, bugfix;
    base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
    if (major < 10 || (major == 10 && minor <= 5)) {
      g_max_output_streams = kMaxOutputStreamsLeopard;
    } else {
      // In OS other than OSX Leopard, the number of audio streams
      // allowed is a lot more.
      g_max_output_streams = kMaxOutputStreams;
    }
  }

  return g_max_output_streams;
}

bool HasAudioHardware(AudioObjectPropertySelector selector) {
  AudioDeviceID output_device_id = kAudioObjectUnknown;
  const AudioObjectPropertyAddress property_address = {
    selector,
    kAudioObjectPropertyScopeGlobal,            // mScope
    kAudioObjectPropertyElementMaster           // mElement
  };
  size_t output_device_id_size = sizeof(output_device_id);
  OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject,
                                            &property_address,
                                            0,     // inQualifierDataSize
                                            NULL,  // inQualifierData
                                            &output_device_id_size,
                                            &output_device_id);
  return err == kAudioHardwareNoError &&
      output_device_id != kAudioObjectUnknown;
}
}  // namespace

AudioManagerMac::AudioManagerMac()
    : num_output_streams_(0) {
}

AudioManagerMac::~AudioManagerMac() {
}

bool AudioManagerMac::HasAudioOutputDevices() {
  return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
}

bool AudioManagerMac::HasAudioInputDevices() {
  return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
}

AudioOutputStream* AudioManagerMac::MakeAudioOutputStream(
    AudioParameters params) {
  if (params.format == AudioParameters::AUDIO_MOCK) {
    return FakeAudioOutputStream::MakeFakeStream(params);
  } else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) {
    return NULL;
  }

  // Limit the number of audio streams opened. This is to prevent using
  // excessive resources for a large number of audio streams. More
  // importantly it prevents instability on certain systems.
  // See bug: http://crbug.com/30242
  if (num_output_streams_ >= GetMaxAudioOutputStreamsAllowed()) {
    return NULL;
  }

  num_output_streams_++;
  return new PCMQueueOutAudioOutputStream(this, params);
}

AudioInputStream* AudioManagerMac::MakeAudioInputStream(
    AudioParameters params) {
  if (!params.IsValid() || (params.channels > kMaxInputChannels))
    return NULL;

  if (params.format == AudioParameters::AUDIO_MOCK) {
    return FakeAudioInputStream::MakeFakeStream(params);
  } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) {
    return new PCMQueueInAudioInputStream(this, params);
  }
  return NULL;
}

void AudioManagerMac::MuteAll() {
  // TODO(cpu): implement.
}

void AudioManagerMac::UnMuteAll() {
  // TODO(cpu): implement.
}

// Called by the stream when it has been released by calling Close().
void AudioManagerMac::ReleaseOutputStream(
    PCMQueueOutAudioOutputStream* stream) {
  DCHECK(stream);
  num_output_streams_--;
  delete stream;
}

// Called by the stream when it has been released by calling Close().
void AudioManagerMac::ReleaseInputStream(PCMQueueInAudioInputStream* stream) {
  delete stream;
}

// static
AudioManager* AudioManager::CreateAudioManager() {
  return new AudioManagerMac();
}