1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "APM::HwModule"
18//#define LOG_NDEBUG 0
19
20#include "HwModule.h"
21#include "IOProfile.h"
22#include "AudioGain.h"
23#include <policy.h>
24#include <system/audio.h>
25
26namespace android {
27
28HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
29    : mName(String8(name)),
30      mHandle(AUDIO_MODULE_HANDLE_NONE)
31{
32    setHalVersion(halVersionMajor, halVersionMinor);
33}
34
35HwModule::~HwModule()
36{
37    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
38        mOutputProfiles[i]->clearSupportedDevices();
39    }
40    for (size_t i = 0; i < mInputProfiles.size(); i++) {
41        mInputProfiles[i]->clearSupportedDevices();
42    }
43}
44
45status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
46                                    audio_devices_t device, const String8& address)
47{
48    sp<IOProfile> profile = new OutputProfile(name);
49
50    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
51                                              config->sample_rate));
52
53    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
54    devDesc->mAddress = address;
55    profile->addSupportedDevice(devDesc);
56
57    return addOutputProfile(profile);
58}
59
60status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
61{
62    profile->attach(this);
63    mOutputProfiles.add(profile);
64    mPorts.add(profile);
65    return NO_ERROR;
66}
67
68status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
69{
70    profile->attach(this);
71    mInputProfiles.add(profile);
72    mPorts.add(profile);
73    return NO_ERROR;
74}
75
76status_t HwModule::addProfile(const sp<IOProfile> &profile)
77{
78    switch (profile->getRole()) {
79    case AUDIO_PORT_ROLE_SOURCE:
80        return addOutputProfile(profile);
81    case AUDIO_PORT_ROLE_SINK:
82        return addInputProfile(profile);
83    case AUDIO_PORT_ROLE_NONE:
84        return BAD_VALUE;
85    }
86    return BAD_VALUE;
87}
88
89void HwModule::setProfiles(const IOProfileCollection &profiles)
90{
91    for (size_t i = 0; i < profiles.size(); i++) {
92        addProfile(profiles[i]);
93    }
94}
95
96status_t HwModule::removeOutputProfile(const String8& name)
97{
98    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
99        if (mOutputProfiles[i]->getName() == name) {
100            mOutputProfiles.removeAt(i);
101            break;
102        }
103    }
104
105    return NO_ERROR;
106}
107
108status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
109                                   audio_devices_t device, const String8& address)
110{
111    sp<IOProfile> profile = new InputProfile(name);
112    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
113                                              config->sample_rate));
114
115    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
116    devDesc->mAddress = address;
117    profile->addSupportedDevice(devDesc);
118
119    ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
120          name.string(), config->sample_rate, config->channel_mask);
121
122    return addInputProfile(profile);
123}
124
125status_t HwModule::removeInputProfile(const String8& name)
126{
127    for (size_t i = 0; i < mInputProfiles.size(); i++) {
128        if (mInputProfiles[i]->getName() == name) {
129            mInputProfiles.removeAt(i);
130            break;
131        }
132    }
133
134    return NO_ERROR;
135}
136
137void HwModule::setDeclaredDevices(const DeviceVector &devices)
138{
139    mDeclaredDevices = devices;
140    for (size_t i = 0; i < devices.size(); i++) {
141        mPorts.add(devices[i]);
142    }
143}
144
145sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
146{
147    sp<DeviceDescriptor> sinkDevice = 0;
148    if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
149        sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
150    }
151    return sinkDevice;
152}
153
154DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
155{
156    DeviceVector sourceDevices;
157    Vector <sp<AudioPort> > sources = route->getSources();
158    for (size_t i = 0; i < sources.size(); i++) {
159        if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
160            sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
161        }
162    }
163    return sourceDevices;
164}
165
166void HwModule::setRoutes(const AudioRouteVector &routes)
167{
168    mRoutes = routes;
169    // Now updating the streams (aka IOProfile until now) supported devices
170    refreshSupportedDevices();
171}
172
173void HwModule::refreshSupportedDevices()
174{
175    // Now updating the streams (aka IOProfile until now) supported devices
176    for (size_t i = 0; i < mInputProfiles.size(); i++) {
177        sp<IOProfile> stream = mInputProfiles[i];
178        DeviceVector sourceDevices;
179        const AudioRouteVector &routes = stream->getRoutes();
180        for (size_t j = 0; j < routes.size(); j++) {
181            sp<AudioPort> sink = routes[j]->getSink();
182            if (sink == 0 || stream != sink) {
183                ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
184                continue;
185            }
186            DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
187            if (sourceDevicesForRoute.isEmpty()) {
188                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
189                continue;
190            }
191            sourceDevices.add(sourceDevicesForRoute);
192        }
193        if (sourceDevices.isEmpty()) {
194            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
195            continue;
196        }
197        stream->setSupportedDevices(sourceDevices);
198    }
199    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
200        sp<IOProfile> stream = mOutputProfiles[i];
201        DeviceVector sinkDevices;
202        const AudioRouteVector &routes = stream->getRoutes();
203        for (size_t j = 0; j < routes.size(); j++) {
204            sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
205            if (source == 0 || stream != source) {
206                ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
207                continue;
208            }
209            sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
210            if (sinkDevice == 0) {
211                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
212                continue;
213            }
214            sinkDevices.add(sinkDevice);
215        }
216        stream->setSupportedDevices(sinkDevices);
217    }
218}
219
220void HwModule::dump(int fd)
221{
222    const size_t SIZE = 256;
223    char buffer[SIZE];
224    String8 result;
225
226    snprintf(buffer, SIZE, "  - name: %s\n", getName());
227    result.append(buffer);
228    snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
229    result.append(buffer);
230    snprintf(buffer, SIZE, "  - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
231    result.append(buffer);
232    write(fd, result.string(), result.size());
233    if (mOutputProfiles.size()) {
234        write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
235        for (size_t i = 0; i < mOutputProfiles.size(); i++) {
236            snprintf(buffer, SIZE, "    output %zu:\n", i);
237            write(fd, buffer, strlen(buffer));
238            mOutputProfiles[i]->dump(fd);
239        }
240    }
241    if (mInputProfiles.size()) {
242        write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
243        for (size_t i = 0; i < mInputProfiles.size(); i++) {
244            snprintf(buffer, SIZE, "    input %zu:\n", i);
245            write(fd, buffer, strlen(buffer));
246            mInputProfiles[i]->dump(fd);
247        }
248    }
249    mDeclaredDevices.dump(fd, String8("Declared"),  2, true);
250    mRoutes.dump(fd, 2);
251}
252
253sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
254{
255    sp <HwModule> module;
256
257    for (size_t i = 0; i < size(); i++)
258    {
259        if (strcmp(itemAt(i)->getName(), name) == 0) {
260            return itemAt(i);
261        }
262    }
263    return module;
264}
265
266
267sp <HwModule> HwModuleCollection::getModuleForDevice(audio_devices_t device) const
268{
269    sp <HwModule> module;
270
271    for (size_t i = 0; i < size(); i++) {
272        if (itemAt(i)->getHandle() == 0) {
273            continue;
274        }
275        if (audio_is_output_device(device)) {
276            for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
277            {
278                if (itemAt(i)->mOutputProfiles[j]->supportDevice(device)) {
279                    return itemAt(i);
280                }
281            }
282        } else {
283            for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
284                if (itemAt(i)->mInputProfiles[j]->supportDevice(device)) {
285                    return itemAt(i);
286                }
287            }
288        }
289    }
290    return module;
291}
292
293sp<DeviceDescriptor>  HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
294                                                              const char *device_address,
295                                                              const char *device_name,
296                                                              bool matchAdress) const
297{
298    String8 address = (device_address == NULL) ? String8("") : String8(device_address);
299    // handle legacy remote submix case where the address was not always specified
300    if (device_distinguishes_on_address(device) && (address.length() == 0)) {
301        address = String8("0");
302    }
303
304    for (size_t i = 0; i < size(); i++) {
305        const sp<HwModule> hwModule = itemAt(i);
306        if (hwModule->mHandle == 0) {
307            continue;
308        }
309        DeviceVector declaredDevices = hwModule->getDeclaredDevices();
310        DeviceVector deviceList = declaredDevices.getDevicesFromTypeAddr(device, address);
311        if (!deviceList.isEmpty()) {
312            return deviceList.itemAt(0);
313        }
314        if (!matchAdress) {
315            deviceList = declaredDevices.getDevicesFromType(device);
316            if (!deviceList.isEmpty()) {
317                return deviceList.itemAt(0);
318            }
319        }
320    }
321
322    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
323    devDesc->setName(String8(device_name));
324    devDesc->mAddress = address;
325    return devDesc;
326}
327
328status_t HwModuleCollection::dump(int fd) const
329{
330    const size_t SIZE = 256;
331    char buffer[SIZE];
332
333    snprintf(buffer, SIZE, "\nHW Modules dump:\n");
334    write(fd, buffer, strlen(buffer));
335    for (size_t i = 0; i < size(); i++) {
336        snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
337        write(fd, buffer, strlen(buffer));
338        itemAt(i)->dump(fd);
339    }
340    return NO_ERROR;
341}
342
343} //namespace android
344