1 /*
2 *
3 * Copyright 2007, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define LOG_TAG "AudioHwDevice"
19 //#define LOG_NDEBUG 0
20
21 #include <system/audio.h>
22 #include <utils/Log.h>
23
24 #include <audio_utils/spdif/SPDIFDecoder.h>
25 #include <audio_utils/spdif/SPDIFEncoder.h>
26 #include <media/AudioResamplerPublic.h>
27
28 #include "AudioHwDevice.h"
29 #include "AudioStreamOut.h"
30 #include "SpdifStreamIn.h"
31 #include "SpdifStreamOut.h"
32
33 namespace android {
34
35 using media::audio::common::AudioMMapPolicyInfo;
36 using media::audio::common::AudioMMapPolicyType;
37
38 // ----------------------------------------------------------------------------
39
openOutputStream(AudioStreamOut ** ppStreamOut,audio_io_handle_t handle,audio_devices_t deviceType,audio_output_flags_t flags,struct audio_config * config,const char * address)40 status_t AudioHwDevice::openOutputStream(
41 AudioStreamOut **ppStreamOut,
42 audio_io_handle_t handle,
43 audio_devices_t deviceType,
44 audio_output_flags_t flags,
45 struct audio_config *config,
46 const char *address)
47 {
48
49 struct audio_config originalConfig = *config;
50 auto outputStream = new AudioStreamOut(this, flags);
51
52 // Try to open the HAL first using the current format.
53 ALOGV("openOutputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
54 config->format, config->channel_mask);
55 status_t status = outputStream->open(handle, deviceType, config, address);
56
57 if (status != NO_ERROR) {
58 delete outputStream;
59 outputStream = nullptr;
60
61 // FIXME Look at any modification to the config.
62 // The HAL might modify the config to suggest a wrapped format.
63 // Log this so we can see what the HALs are doing.
64 ALOGI("openOutputStream(), HAL returned sampleRate %d, format %#x, channelMask %#x,"
65 " status %d", config->sample_rate, config->format, config->channel_mask, status);
66
67 // If the data is encoded then try again using wrapped PCM.
68 const bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
69 && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
70 && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
71
72 if (wrapperNeeded) {
73 if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
74 outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
75 status = outputStream->open(handle, deviceType, &originalConfig, address);
76 if (status != NO_ERROR) {
77 ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
78 status);
79 delete outputStream;
80 outputStream = nullptr;
81 }
82 } else {
83 ALOGE("ERROR - openOutputStream(), SPDIFEncoder does not support format 0x%08x",
84 originalConfig.format);
85 }
86 }
87 }
88
89 *ppStreamOut = outputStream;
90 return status;
91 }
92
openInputStream(AudioStreamIn ** ppStreamIn,audio_io_handle_t handle,audio_devices_t deviceType,audio_input_flags_t flags,struct audio_config * config,const char * address,audio_source_t source,audio_devices_t outputDevice,const char * outputDeviceAddress)93 status_t AudioHwDevice::openInputStream(
94 AudioStreamIn **ppStreamIn,
95 audio_io_handle_t handle,
96 audio_devices_t deviceType,
97 audio_input_flags_t flags,
98 struct audio_config *config,
99 const char *address,
100 audio_source_t source,
101 audio_devices_t outputDevice,
102 const char *outputDeviceAddress) {
103
104 struct audio_config originalConfig = *config;
105 auto inputStream = new AudioStreamIn(this, flags);
106
107 // Try to open the HAL first using the current format.
108 ALOGV("openInputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
109 config->format, config->channel_mask);
110 status_t status = inputStream->open(handle, deviceType, config, address, source, outputDevice,
111 outputDeviceAddress);
112
113 // If the input could not be opened with the requested parameters and we can handle the
114 // conversion internally, try to open again with the proposed parameters.
115 if (status == BAD_VALUE &&
116 audio_is_linear_pcm(originalConfig.format) &&
117 audio_is_linear_pcm(config->format) &&
118 (config->sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) &&
119 (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_LIMIT) &&
120 (audio_channel_count_from_in_mask(originalConfig.channel_mask) <= FCC_LIMIT)) {
121 // FIXME describe the change proposed by HAL (save old values so we can log them here)
122 ALOGV("openInputStream() reopening with proposed sampling rate and channel mask");
123 status = inputStream->open(handle, deviceType, config, address, source,
124 outputDevice, outputDeviceAddress);
125 // FIXME log this new status; HAL should not propose any further changes
126 if (status != NO_ERROR) {
127 delete inputStream;
128 inputStream = nullptr;
129 }
130 } else if (status != NO_ERROR) {
131 delete inputStream;
132 inputStream = nullptr;
133
134 // FIXME Look at any modification to the config.
135 // The HAL might modify the config to suggest a wrapped format.
136 // Log this so we can see what the HALs are doing.
137 ALOGI("openInputStream(), HAL returned sampleRate %d, format %#x, channelMask %#x,"
138 " status %d", config->sample_rate, config->format, config->channel_mask, status);
139
140 // If the data is encoded then try again using wrapped PCM.
141 const bool unwrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
142 && ((flags & AUDIO_INPUT_FLAG_DIRECT) != 0);
143
144 if (unwrapperNeeded) {
145 if (SPDIFDecoder::isFormatSupported(originalConfig.format)) {
146 inputStream = new SpdifStreamIn(this, flags, originalConfig.format);
147 status = inputStream->open(handle, deviceType, &originalConfig, address, source,
148 outputDevice, outputDeviceAddress);
149 if (status != NO_ERROR) {
150 ALOGE("ERROR - openInputStream(), SPDIF open returned %d",
151 status);
152 delete inputStream;
153 inputStream = nullptr;
154 }
155 } else {
156 ALOGE("ERROR - openInputStream(), SPDIFDecoder does not support format 0x%08x",
157 originalConfig.format);
158 }
159 }
160 }
161
162 *ppStreamIn = inputStream;
163 return status;
164 }
165
supportsAudioPatches() const166 bool AudioHwDevice::supportsAudioPatches() const {
167 bool result;
168 return mHwDevice->supportsAudioPatches(&result) == OK ? result : false;
169 }
170
getAudioPort(struct audio_port_v7 * port) const171 status_t AudioHwDevice::getAudioPort(struct audio_port_v7 *port) const {
172 return mHwDevice->getAudioPort(port);
173 }
174
getMmapPolicyInfos(AudioMMapPolicyType policyType,std::vector<AudioMMapPolicyInfo> * policyInfos) const175 status_t AudioHwDevice::getMmapPolicyInfos(
176 AudioMMapPolicyType policyType, std::vector<AudioMMapPolicyInfo> *policyInfos) const {
177 return mHwDevice->getMmapPolicyInfos(policyType, policyInfos);
178 }
179
getAAudioMixerBurstCount() const180 int32_t AudioHwDevice::getAAudioMixerBurstCount() const {
181 return mHwDevice->getAAudioMixerBurstCount();
182 }
183
getAAudioHardwareBurstMinUsec() const184 int32_t AudioHwDevice::getAAudioHardwareBurstMinUsec() const {
185 return mHwDevice->getAAudioHardwareBurstMinUsec();
186 }
187
getAudioMixPort(const struct audio_port_v7 * devicePort,struct audio_port_v7 * mixPort) const188 status_t AudioHwDevice::getAudioMixPort(const struct audio_port_v7 *devicePort,
189 struct audio_port_v7 *mixPort) const {
190 return mHwDevice->getAudioMixPort(devicePort, mixPort);
191 }
192
193
194 }; // namespace android
195