1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "UsecaseValidator"
17*ec779b8eSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker
19*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #include "media/UsecaseValidator.h"
24*ec779b8eSAndroid Build Coastguard Worker #include "media/UsecaseLookup.h"
25*ec779b8eSAndroid Build Coastguard Worker
26*ec779b8eSAndroid Build Coastguard Worker namespace android {
27*ec779b8eSAndroid Build Coastguard Worker namespace media {
28*ec779b8eSAndroid Build Coastguard Worker namespace {
29*ec779b8eSAndroid Build Coastguard Worker
30*ec779b8eSAndroid Build Coastguard Worker class UsecaseValidatorImpl : public UsecaseValidator {
31*ec779b8eSAndroid Build Coastguard Worker public:
UsecaseValidatorImpl()32*ec779b8eSAndroid Build Coastguard Worker UsecaseValidatorImpl() {}
33*ec779b8eSAndroid Build Coastguard Worker
34*ec779b8eSAndroid Build Coastguard Worker /**
35*ec779b8eSAndroid Build Coastguard Worker * Register a new mixer/stream.
36*ec779b8eSAndroid Build Coastguard Worker * Called when the stream is opened at the HAL and communicates
37*ec779b8eSAndroid Build Coastguard Worker * immutable stream attributes like flags, sampling rate, format.
38*ec779b8eSAndroid Build Coastguard Worker */
registerStream(audio_io_handle_t streamId,const audio_config_base_t & audioConfig,const audio_output_flags_t outputFlags)39*ec779b8eSAndroid Build Coastguard Worker status_t registerStream(audio_io_handle_t streamId,
40*ec779b8eSAndroid Build Coastguard Worker const audio_config_base_t& audioConfig __attribute__((unused)),
41*ec779b8eSAndroid Build Coastguard Worker const audio_output_flags_t outputFlags) override {
42*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s output: %d flags: %#x", __func__, streamId, outputFlags);
43*ec779b8eSAndroid Build Coastguard Worker
44*ec779b8eSAndroid Build Coastguard Worker // Check if FAST or MMAP output flag has been set.
45*ec779b8eSAndroid Build Coastguard Worker bool outputFlagGame = outputFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
46*ec779b8eSAndroid Build Coastguard Worker m_lookup.addStream(streamId, outputFlagGame);
47*ec779b8eSAndroid Build Coastguard Worker return OK;
48*ec779b8eSAndroid Build Coastguard Worker };
49*ec779b8eSAndroid Build Coastguard Worker
50*ec779b8eSAndroid Build Coastguard Worker /**
51*ec779b8eSAndroid Build Coastguard Worker * Unregister a stream/mixer.
52*ec779b8eSAndroid Build Coastguard Worker * Called when the stream is closed.
53*ec779b8eSAndroid Build Coastguard Worker */
unregisterStream(audio_io_handle_t streamId)54*ec779b8eSAndroid Build Coastguard Worker status_t unregisterStream(audio_io_handle_t streamId) override {
55*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s output: %d", __func__, streamId);
56*ec779b8eSAndroid Build Coastguard Worker
57*ec779b8eSAndroid Build Coastguard Worker m_lookup.removeStream(streamId);
58*ec779b8eSAndroid Build Coastguard Worker return OK;
59*ec779b8eSAndroid Build Coastguard Worker };
60*ec779b8eSAndroid Build Coastguard Worker
61*ec779b8eSAndroid Build Coastguard Worker /**
62*ec779b8eSAndroid Build Coastguard Worker * Indicates that some playback activity started on the stream.
63*ec779b8eSAndroid Build Coastguard Worker * Called each time an audio track starts or resumes.
64*ec779b8eSAndroid Build Coastguard Worker */
startClient(audio_io_handle_t streamId,audio_port_handle_t portId,const content::AttributionSourceState & attributionSource,const audio_attributes_t & attributes,const AttributesChangedCallback * callback)65*ec779b8eSAndroid Build Coastguard Worker error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
66*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t portId, const content::AttributionSourceState& attributionSource,
67*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t& attributes,
68*ec779b8eSAndroid Build Coastguard Worker const AttributesChangedCallback *callback __attribute__((unused))) override {
69*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s output: %d portId: %d usage: %d pid: %d package: %s",
70*ec779b8eSAndroid Build Coastguard Worker __func__, streamId, portId, attributes.usage, attributionSource.pid,
71*ec779b8eSAndroid Build Coastguard Worker attributionSource.packageName.value_or("").c_str());
72*ec779b8eSAndroid Build Coastguard Worker
73*ec779b8eSAndroid Build Coastguard Worker m_lookup.addTrack(streamId, portId);
74*ec779b8eSAndroid Build Coastguard Worker
75*ec779b8eSAndroid Build Coastguard Worker return verifyAudioAttributes(streamId, attributionSource, attributes);
76*ec779b8eSAndroid Build Coastguard Worker };
77*ec779b8eSAndroid Build Coastguard Worker
78*ec779b8eSAndroid Build Coastguard Worker /**
79*ec779b8eSAndroid Build Coastguard Worker * Indicates that some playback activity stopped on the stream.
80*ec779b8eSAndroid Build Coastguard Worker * Called each time an audio track stops or pauses.
81*ec779b8eSAndroid Build Coastguard Worker */
stopClient(audio_io_handle_t streamId,audio_port_handle_t portId)82*ec779b8eSAndroid Build Coastguard Worker status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) override {
83*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s output: %d portId: %d", __func__, streamId, portId);
84*ec779b8eSAndroid Build Coastguard Worker
85*ec779b8eSAndroid Build Coastguard Worker m_lookup.removeTrack(streamId, portId);
86*ec779b8eSAndroid Build Coastguard Worker return OK;
87*ec779b8eSAndroid Build Coastguard Worker };
88*ec779b8eSAndroid Build Coastguard Worker
89*ec779b8eSAndroid Build Coastguard Worker /**
90*ec779b8eSAndroid Build Coastguard Worker * Called to verify and update audio attributes for a track that is connected
91*ec779b8eSAndroid Build Coastguard Worker * to the specified stream.
92*ec779b8eSAndroid Build Coastguard Worker */
verifyAudioAttributes(audio_io_handle_t streamId,const content::AttributionSourceState & attributionSource,const audio_attributes_t & attributes)93*ec779b8eSAndroid Build Coastguard Worker error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
94*ec779b8eSAndroid Build Coastguard Worker const content::AttributionSourceState& attributionSource,
95*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t& attributes) override {
96*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s output: %d usage: %d pid: %d package: %s",
97*ec779b8eSAndroid Build Coastguard Worker __func__, streamId, attributes.usage, attributionSource.pid,
98*ec779b8eSAndroid Build Coastguard Worker attributionSource.packageName.value_or("").c_str());
99*ec779b8eSAndroid Build Coastguard Worker
100*ec779b8eSAndroid Build Coastguard Worker audio_attributes_t attrRet = attributes;
101*ec779b8eSAndroid Build Coastguard Worker
102*ec779b8eSAndroid Build Coastguard Worker if (isUsageValid(attributes.usage) && isContentTypeValid(attributes.content_type)
103*ec779b8eSAndroid Build Coastguard Worker && areFlagsValid(attributes.flags) && m_lookup.isGameStream(streamId)) {
104*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s update usage: %d to AUDIO_USAGE_GAME for output: %d pid: %d package: %s",
105*ec779b8eSAndroid Build Coastguard Worker __func__, attributes.usage, streamId, attributionSource.pid,
106*ec779b8eSAndroid Build Coastguard Worker attributionSource.packageName.value_or("").c_str());
107*ec779b8eSAndroid Build Coastguard Worker // Set attribute usage Game.
108*ec779b8eSAndroid Build Coastguard Worker attrRet.usage = AUDIO_USAGE_GAME;
109*ec779b8eSAndroid Build Coastguard Worker }
110*ec779b8eSAndroid Build Coastguard Worker
111*ec779b8eSAndroid Build Coastguard Worker return {attrRet};
112*ec779b8eSAndroid Build Coastguard Worker };
113*ec779b8eSAndroid Build Coastguard Worker
114*ec779b8eSAndroid Build Coastguard Worker protected:
115*ec779b8eSAndroid Build Coastguard Worker /**
116*ec779b8eSAndroid Build Coastguard Worker * Check if attribute usage valid.
117*ec779b8eSAndroid Build Coastguard Worker */
isUsageValid(audio_usage_t usage)118*ec779b8eSAndroid Build Coastguard Worker bool isUsageValid(audio_usage_t usage) {
119*ec779b8eSAndroid Build Coastguard Worker ALOGV("isUsageValid usage: %d", usage);
120*ec779b8eSAndroid Build Coastguard Worker switch (usage) {
121*ec779b8eSAndroid Build Coastguard Worker case AUDIO_USAGE_MEDIA:
122*ec779b8eSAndroid Build Coastguard Worker case AUDIO_USAGE_UNKNOWN:
123*ec779b8eSAndroid Build Coastguard Worker return true;
124*ec779b8eSAndroid Build Coastguard Worker default:
125*ec779b8eSAndroid Build Coastguard Worker break;
126*ec779b8eSAndroid Build Coastguard Worker }
127*ec779b8eSAndroid Build Coastguard Worker return false;
128*ec779b8eSAndroid Build Coastguard Worker }
129*ec779b8eSAndroid Build Coastguard Worker
isContentTypeValid(audio_content_type_t contentType)130*ec779b8eSAndroid Build Coastguard Worker bool isContentTypeValid(audio_content_type_t contentType) {
131*ec779b8eSAndroid Build Coastguard Worker ALOGV("isContentTypeValid contentType: %d", contentType);
132*ec779b8eSAndroid Build Coastguard Worker switch (contentType) {
133*ec779b8eSAndroid Build Coastguard Worker case AUDIO_CONTENT_TYPE_MUSIC:
134*ec779b8eSAndroid Build Coastguard Worker case AUDIO_CONTENT_TYPE_MOVIE:
135*ec779b8eSAndroid Build Coastguard Worker case AUDIO_CONTENT_TYPE_UNKNOWN:
136*ec779b8eSAndroid Build Coastguard Worker return true;
137*ec779b8eSAndroid Build Coastguard Worker default:
138*ec779b8eSAndroid Build Coastguard Worker break;
139*ec779b8eSAndroid Build Coastguard Worker }
140*ec779b8eSAndroid Build Coastguard Worker return false;
141*ec779b8eSAndroid Build Coastguard Worker }
142*ec779b8eSAndroid Build Coastguard Worker
areFlagsValid(audio_flags_mask_t flags)143*ec779b8eSAndroid Build Coastguard Worker bool areFlagsValid(audio_flags_mask_t flags) {
144*ec779b8eSAndroid Build Coastguard Worker ALOGV("areFlagsValid flags: %#x", flags);
145*ec779b8eSAndroid Build Coastguard Worker if ((flags & (AUDIO_FLAG_SCO|AUDIO_FLAG_AUDIBILITY_ENFORCED|AUDIO_FLAG_BEACON)) != 0) {
146*ec779b8eSAndroid Build Coastguard Worker return false;
147*ec779b8eSAndroid Build Coastguard Worker }
148*ec779b8eSAndroid Build Coastguard Worker if ((flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
149*ec779b8eSAndroid Build Coastguard Worker return true;
150*ec779b8eSAndroid Build Coastguard Worker }
151*ec779b8eSAndroid Build Coastguard Worker return false;
152*ec779b8eSAndroid Build Coastguard Worker }
153*ec779b8eSAndroid Build Coastguard Worker
154*ec779b8eSAndroid Build Coastguard Worker protected:
155*ec779b8eSAndroid Build Coastguard Worker UsecaseLookup m_lookup;
156*ec779b8eSAndroid Build Coastguard Worker };
157*ec779b8eSAndroid Build Coastguard Worker
158*ec779b8eSAndroid Build Coastguard Worker } // namespace
159*ec779b8eSAndroid Build Coastguard Worker
createUsecaseValidator()160*ec779b8eSAndroid Build Coastguard Worker std::unique_ptr<UsecaseValidator> createUsecaseValidator() {
161*ec779b8eSAndroid Build Coastguard Worker return std::make_unique<UsecaseValidatorImpl>();
162*ec779b8eSAndroid Build Coastguard Worker }
163*ec779b8eSAndroid Build Coastguard Worker
164*ec779b8eSAndroid Build Coastguard Worker } // namespace media
165*ec779b8eSAndroid Build Coastguard Worker } // namespace android
166