1c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk/*
2c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Copyright (C) 2017 The Android Open Source Project
3c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
4c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Licensed under the Apache License, Version 2.0 (the "License");
5c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * you may not use this file except in compliance with the License.
6c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * You may obtain a copy of the License at
7c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
8c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *      http://www.apache.org/licenses/LICENSE-2.0
9c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk *
10c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * Unless required by applicable law or agreed to in writing, software
11c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * distributed under the License is distributed on an "AS IS" BASIS,
12c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * See the License for the specific language governing permissions and
14c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk * limitations under the License.
15c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk */
16c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
17c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
18fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk#define LOG_TAG "AAudioBinderClient"
19c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk//#define LOG_NDEBUG 0
20c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utils/Log.h>
21c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
2211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk#include <binder/IInterface.h>
23c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <binder/IServiceManager.h>
2411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk#include <binder/ProcessState.h>
25c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utils/Mutex.h>
26c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utils/RefBase.h>
279b3f8ef290bd5ad392f5eba8a0f0a8ddd331b54fPhil Burk#include <utils/Singleton.h>
2811e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk#include <media/AudioSystem.h>
29c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
30c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <aaudio/AAudio.h>
31c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
32c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioEndpointParcelable.h"
3311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk#include "binding/AAudioBinderClient.h"
3411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk//#include "binding/AAudioStreamRequest.h"
3511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk//#include "binding/AAudioStreamConfiguration.h"
3611e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk//#include "binding/IAAudioService.h"
3711e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk//#include "binding/AAudioServiceMessage.h"
38c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
3911e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk//#include "AAudioServiceInterface.h"
40c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
41c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::String16;
42c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::IServiceManager;
43c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::defaultServiceManager;
44c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::interface_cast;
4511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burkusing android::IInterface;
46c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::IAAudioService;
47c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::Mutex;
482bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burkusing android::ProcessState;
49c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::sp;
5011e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burkusing android::wp;
51c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
52c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing namespace aaudio;
53c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
549b3f8ef290bd5ad392f5eba8a0f0a8ddd331b54fPhil BurkANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient);
559b3f8ef290bd5ad392f5eba8a0f0a8ddd331b54fPhil Burk
562bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk// If we don't keep a strong pointer here then this singleton can get deleted!
572bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burkandroid::sp<AAudioBinderClient> gKeepBinderClient;
582bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk
5911e8d335b1da528ee771b19b63df23ae6fd52f41Phil BurkAAudioBinderClient::AAudioBinderClient()
6011e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        : AAudioServiceInterface()
6111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        , Singleton<AAudioBinderClient>() {
622bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    gKeepBinderClient = this; // so this singleton won't get deleted
6311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    mAAudioClient = new AAudioClient(this);
64fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGV("%s - this = %p, created mAAudioClient = %p", __func__, this, mAAudioClient.get());
6511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk}
6611e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk
6711e8d335b1da528ee771b19b63df23ae6fd52f41Phil BurkAAudioBinderClient::~AAudioBinderClient() {
68fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGV("%s - destroying %p", __func__, this);
6911e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    Mutex::Autolock _l(mServiceLock);
7011e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    if (mAAudioService != 0) {
7111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
7211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    }
7311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk}
7411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk
75c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk// TODO Share code with other service clients.
76c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk// Helper function to get access to the "AAudioService" service.
77c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
7811e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burkconst sp<IAAudioService> AAudioBinderClient::getAAudioService() {
7911e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    sp<IAAudioService> aaudioService;
8011e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    bool needToRegister = false;
8111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    {
8211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        Mutex::Autolock _l(mServiceLock);
832bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk        if (mAAudioService.get() == nullptr) {
8411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            sp<IBinder> binder;
8511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            sp<IServiceManager> sm = defaultServiceManager();
8611e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            // Try several times to get the service.
8711e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            int retries = 4;
8811e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            do {
8911e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
902bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk                if (binder.get() != nullptr) {
9111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                    break;
9211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                }
9311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            } while (retries-- > 0);
9411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk
952bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk            if (binder.get() != nullptr) {
9611e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                // Ask for notification if the service dies.
9711e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                status_t status = binder->linkToDeath(mAAudioClient);
98c7abac4329e15cda4bbbd25f8fc4a93b70d70d0aPhil Burk                // TODO review what we should do if this fails
99c7abac4329e15cda4bbbd25f8fc4a93b70d70d0aPhil Burk                if (status != NO_ERROR) {
100c7abac4329e15cda4bbbd25f8fc4a93b70d70d0aPhil Burk                    ALOGE("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
101c7abac4329e15cda4bbbd25f8fc4a93b70d70d0aPhil Burk                          mAAudioClient.get(), status);
102c7abac4329e15cda4bbbd25f8fc4a93b70d70d0aPhil Burk                }
10311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                mAAudioService = interface_cast<IAAudioService>(binder);
10411e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                needToRegister = true;
10511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                // Make sure callbacks can be received by mAAudioClient
1062bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk                ProcessState::self()->startThreadPool();
10711e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk            } else {
10811e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk                ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
109c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            }
110c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        }
11111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        aaudioService = mAAudioService;
11211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    }
11311e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    // Do this outside the mutex lock.
1142bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (needToRegister && aaudioService.get() != nullptr) { // new client?
11511e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk        aaudioService->registerClient(mAAudioClient);
116c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
11711e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    return aaudioService;
118c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
119c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
12011e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burkvoid AAudioBinderClient::dropAAudioService() {
12111e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    Mutex::Autolock _l(mServiceLock);
12211e8d335b1da528ee771b19b63df23ae6fd52f41Phil Burk    mAAudioService.clear(); // force a reconnect
12371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk}
124c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
125c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk/**
126c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk* @param request info needed to create the stream
127c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk* @param configuration contains information about the created stream
128c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk* @return handle to the stream or a negative error
129c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk*/
130c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_handle_t AAudioBinderClient::openStream(const AAudioStreamRequest &request,
131c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                               AAudioStreamConfiguration &configurationOutput) {
13271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    aaudio_handle_t stream;
13371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    for (int i = 0; i < 2; i++) {
13471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        const sp<IAAudioService> &service = getAAudioService();
1352bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk        if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
136c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
13771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        stream = service->openStream(request, configurationOutput);
13871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk
13971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        if (stream == AAUDIO_ERROR_NO_SERVICE) {
140fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk            ALOGE("openStream lost connection to AAudioService.");
14171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk            dropAAudioService(); // force a reconnect
14271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        } else {
14371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk            break;
14471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        }
14571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    }
14671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    return stream;
147c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
148c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
149c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::closeStream(aaudio_handle_t streamHandle) {
1502bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1512bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
152c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return service->closeStream(streamHandle);
153c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
154c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
155c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk/* Get an immutable description of the in-memory queues
156c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk* used to communicate with the underlying HAL or Service.
157c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk*/
158c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
159c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                                         AudioEndpointParcelable &parcelable) {
1602bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1612bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
162c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return service->getStreamDescription(streamHandle, parcelable);
163c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
164c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
165c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::startStream(aaudio_handle_t streamHandle) {
1662bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1672bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
168c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return service->startStream(streamHandle);
169c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
170c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
171c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::pauseStream(aaudio_handle_t streamHandle) {
1722bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1732bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
17471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    return service->pauseStream(streamHandle);
17571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk}
17671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk
17771f35bb687476694882a617ba4a810a0bb56fe23Phil Burkaaudio_result_t AAudioBinderClient::stopStream(aaudio_handle_t streamHandle) {
1782bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1792bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
18071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    return service->stopStream(streamHandle);
181c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
182c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
183c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) {
1842bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1852bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
18671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    return service->flushStream(streamHandle);
187c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
188c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
189c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk/**
190c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk* Manage the specified thread as a low latency audio thread.
191c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk*/
192c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
193c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                                        pid_t clientThreadId,
194c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                                        int64_t periodNanoseconds) {
1952bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
1962bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
197c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return service->registerAudioThread(streamHandle,
198c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                        clientThreadId,
199c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                        periodNanoseconds);
200c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
201c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
202c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
203c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                                          pid_t clientThreadId) {
2042bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    const sp<IAAudioService> service = getAAudioService();
2052bc7c1838703993e126bfe9a21fee053b6c0ab67Phil Burk    if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
206c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return service->unregisterAudioThread(streamHandle,
207c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk                                          clientThreadId);
208c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
209