• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 "AAudioServiceStreamMMAP"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <atomic>
22 #include <iomanip>
23 #include <iostream>
24 #include <stdint.h>
25 
26 #include <utils/String16.h>
27 #include <media/nbaio/AudioStreamOutSink.h>
28 #include <media/MmapStreamInterface.h>
29 
30 #include "binding/AudioEndpointParcelable.h"
31 #include "utility/AAudioUtilities.h"
32 
33 #include "AAudioServiceEndpointMMAP.h"
34 #include "AAudioServiceStreamBase.h"
35 #include "AAudioServiceStreamMMAP.h"
36 #include "SharedMemoryProxy.h"
37 
38 using android::base::unique_fd;
39 using namespace android;
40 using namespace aaudio;
41 
42 /**
43  * Service Stream that uses an MMAP buffer.
44  */
45 
AAudioServiceStreamMMAP(android::AAudioService & aAudioService,bool inService)46 AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
47                                                  bool inService)
48         : AAudioServiceStreamBase(aAudioService)
49         , mInService(inService) {
50 }
51 
52 // Open stream on HAL and pass information about the shared memory buffer back to the client.
open(const aaudio::AAudioStreamRequest & request)53 aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
54 
55     sp<AAudioServiceStreamMMAP> keep(this);
56 
57     if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) {
58         ALOGE("%s() sharingMode mismatch %d", __func__,
59               request.getConstantConfiguration().getSharingMode());
60         return AAUDIO_ERROR_INTERNAL;
61     }
62 
63     aaudio_result_t result = AAudioServiceStreamBase::open(request);
64     if (result != AAUDIO_OK) {
65         return result;
66     }
67 
68     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
69     if (endpoint == nullptr) {
70         ALOGE("%s() has no endpoint", __func__);
71         return AAUDIO_ERROR_INVALID_STATE;
72     }
73 
74     result = endpoint->registerStream(keep);
75     if (result != AAUDIO_OK) {
76         return result;
77     }
78 
79     setState(AAUDIO_STREAM_STATE_OPEN);
80 
81     return AAUDIO_OK;
82 }
83 
84 // Start the flow of data.
startDevice()85 aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
86     aaudio_result_t result = AAudioServiceStreamBase::startDevice();
87     if (!mInService && result == AAUDIO_OK) {
88         // Note that this can sometimes take 200 to 300 msec for a cold start!
89         result = startClient(mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
90     }
91     return result;
92 }
93 
94 // Stop the flow of data such that start() can resume with loss of data.
pause_l()95 aaudio_result_t AAudioServiceStreamMMAP::pause_l() {
96     if (!isRunning()) {
97         return AAUDIO_OK;
98     }
99     aaudio_result_t result = AAudioServiceStreamBase::pause_l();
100     // TODO put before base::pause()?
101     if (!mInService) {
102         (void) stopClient(mClientHandle);
103     }
104     return result;
105 }
106 
stop_l()107 aaudio_result_t AAudioServiceStreamMMAP::stop_l() {
108     if (!isRunning()) {
109         return AAUDIO_OK;
110     }
111     aaudio_result_t result = AAudioServiceStreamBase::stop_l();
112     // TODO put before base::stop()?
113     if (!mInService) {
114         (void) stopClient(mClientHandle);
115     }
116     return result;
117 }
118 
startClient(const android::AudioClient & client,const audio_attributes_t * attr,audio_port_handle_t * clientHandle)119 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
120                                                      const audio_attributes_t *attr,
121                                                      audio_port_handle_t *clientHandle) {
122     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
123     if (endpoint == nullptr) {
124         ALOGE("%s() has no endpoint", __func__);
125         return AAUDIO_ERROR_INVALID_STATE;
126     }
127     // Start the client on behalf of the application. Generate a new porthandle.
128     aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
129     return result;
130 }
131 
stopClient(audio_port_handle_t clientHandle)132 aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
133     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
134     if (endpoint == nullptr) {
135         ALOGE("%s() has no endpoint", __func__);
136         return AAUDIO_ERROR_INVALID_STATE;
137     }
138     aaudio_result_t result = endpoint->stopClient(clientHandle);
139     return result;
140 }
141 
142 // Get free-running DSP or DMA hardware position from the HAL.
getFreeRunningPosition(int64_t * positionFrames,int64_t * timeNanos)143 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
144                                                                   int64_t *timeNanos) {
145     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
146     if (endpoint == nullptr) {
147         ALOGE("%s() has no endpoint", __func__);
148         return AAUDIO_ERROR_INVALID_STATE;
149     }
150     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
151             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
152 
153     aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
154     if (result == AAUDIO_OK) {
155         Timestamp timestamp(*positionFrames, *timeNanos);
156         mAtomicStreamTimestamp.write(timestamp);
157         *positionFrames = timestamp.getPosition();
158         *timeNanos = timestamp.getNanoseconds();
159     } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
160         disconnect();
161     }
162     return result;
163 }
164 
165 // Get timestamp that was written by getFreeRunningPosition()
getHardwareTimestamp(int64_t * positionFrames,int64_t * timeNanos)166 aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames,
167                                                                 int64_t *timeNanos) {
168 
169     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
170     if (endpoint == nullptr) {
171         ALOGE("%s() has no endpoint", __func__);
172         return AAUDIO_ERROR_INVALID_STATE;
173     }
174     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
175             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
176 
177     // TODO Get presentation timestamp from the HAL
178     if (mAtomicStreamTimestamp.isValid()) {
179         Timestamp timestamp = mAtomicStreamTimestamp.read();
180         *positionFrames = timestamp.getPosition();
181         *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
182         return AAUDIO_OK;
183     } else {
184         return AAUDIO_ERROR_UNAVAILABLE;
185     }
186 }
187 
188 // Get an immutable description of the data queue from the HAL.
getAudioDataDescription(AudioEndpointParcelable & parcelable)189 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
190         AudioEndpointParcelable &parcelable)
191 {
192     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
193     if (endpoint == nullptr) {
194         ALOGE("%s() has no endpoint", __func__);
195         return AAUDIO_ERROR_INVALID_STATE;
196     }
197     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
198             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
199     return serviceEndpointMMAP->getDownDataDescription(parcelable);
200 }
201