Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /*
4 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
5 * Copyright (C) 2008 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
20 #include <stagefright/foundation/ADebug.h>
21 #include "AudioOutput.h"
23 namespace mozilla {
25 #ifdef PR_LOGGING
26 extern PRLogModuleInfo* gAudioOffloadPlayerLog;
27 #define AUDIO_OFFLOAD_LOG(type, msg) \
28 PR_LOG(gAudioOffloadPlayerLog, type, msg)
29 #else
30 #define AUDIO_OFFLOAD_LOG(type, msg)
31 #endif
33 using namespace android;
35 AudioOutput::AudioOutput(int aSessionId, int aUid) :
36 mCallback(nullptr),
37 mCallbackCookie(nullptr),
38 mCallbackData(nullptr),
39 mSessionId(aSessionId),
40 mUid(aUid)
41 {
42 #ifdef PR_LOGGING
43 if (!gAudioOffloadPlayerLog) {
44 gAudioOffloadPlayerLog = PR_NewLogModule("AudioOffloadPlayer");
45 }
46 #endif
47 }
49 AudioOutput::~AudioOutput()
50 {
51 Close();
52 }
54 ssize_t AudioOutput::FrameSize() const
55 {
56 if (!mTrack.get()) {
57 return NO_INIT;
58 }
59 return mTrack->frameSize();
60 }
62 status_t AudioOutput::GetPosition(uint32_t *aPosition) const
63 {
64 if (!mTrack.get()) {
65 return NO_INIT;
66 }
67 return mTrack->getPosition(aPosition);
68 }
70 status_t AudioOutput::SetVolume(float aVolume) const
71 {
72 if (!mTrack.get()) {
73 return NO_INIT;
74 }
75 return mTrack->setVolume(aVolume);
76 }
78 status_t AudioOutput::SetParameters(const String8& aKeyValuePairs)
79 {
80 if (!mTrack.get()) {
81 return NO_INIT;
82 }
83 return mTrack->setParameters(aKeyValuePairs);
84 }
86 status_t AudioOutput::Open(uint32_t aSampleRate,
87 int aChannelCount,
88 audio_channel_mask_t aChannelMask,
89 audio_format_t aFormat,
90 AudioCallback aCb,
91 void* aCookie,
92 audio_output_flags_t aFlags,
93 const audio_offload_info_t *aOffloadInfo)
94 {
95 mCallback = aCb;
96 mCallbackCookie = aCookie;
98 if (((aFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || !aCb ||
99 !aOffloadInfo) {
100 return BAD_VALUE;
101 }
103 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("open(%u, %d, 0x%x, 0x%x, %d 0x%x)",
104 aSampleRate, aChannelCount, aChannelMask, aFormat, mSessionId, aFlags));
106 if (aChannelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
107 aChannelMask = audio_channel_out_mask_from_count(aChannelCount);
108 if (0 == aChannelMask) {
109 AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("open() error, can\'t derive mask for"
110 " %d audio channels", aChannelCount));
111 return NO_INIT;
112 }
113 }
115 sp<AudioTrack> t;
116 CallbackData* newcbd = new CallbackData(this);
118 t = new AudioTrack(
119 AUDIO_STREAM_MUSIC,
120 aSampleRate,
121 aFormat,
122 aChannelMask,
123 0, // Offloaded tracks will get frame count from AudioFlinger
124 aFlags,
125 CallbackWrapper,
126 newcbd,
127 0, // notification frames
128 mSessionId,
129 AudioTrack::TRANSFER_CALLBACK,
130 aOffloadInfo,
131 mUid);
133 if ((!t.get()) || (t->initCheck() != NO_ERROR)) {
134 AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Unable to create audio track"));
135 delete newcbd;
136 return NO_INIT;
137 }
139 mCallbackData = newcbd;
140 t->setVolume(1.0);
142 mTrack = t;
143 return NO_ERROR;
144 }
146 status_t AudioOutput::Start()
147 {
148 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
149 if (!mTrack.get()) {
150 return NO_INIT;
151 }
152 mTrack->setVolume(1.0);
153 return mTrack->start();
154 }
156 void AudioOutput::Stop()
157 {
158 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
159 if (mTrack.get()) {
160 mTrack->stop();
161 }
162 }
164 void AudioOutput::Flush()
165 {
166 if (mTrack.get()) {
167 mTrack->flush();
168 }
169 }
171 void AudioOutput::Pause()
172 {
173 if (mTrack.get()) {
174 mTrack->pause();
175 }
176 }
178 void AudioOutput::Close()
179 {
180 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
181 mTrack.clear();
183 delete mCallbackData;
184 mCallbackData = nullptr;
185 }
187 // static
188 void AudioOutput::CallbackWrapper(int aEvent, void* aCookie, void* aInfo)
189 {
190 CallbackData* data = (CallbackData*) aCookie;
191 data->Lock();
192 AudioOutput* me = data->GetOutput();
193 AudioTrack::Buffer* buffer = (AudioTrack::Buffer*) aInfo;
194 if (!me) {
195 // no output set, likely because the track was scheduled to be reused
196 // by another player, but the format turned out to be incompatible.
197 data->Unlock();
198 if (buffer) {
199 buffer->size = 0;
200 }
201 return;
202 }
204 switch(aEvent) {
206 case AudioTrack::EVENT_MORE_DATA: {
208 size_t actualSize = (*me->mCallback)(me, buffer->raw, buffer->size,
209 me->mCallbackCookie, CB_EVENT_FILL_BUFFER);
211 if (actualSize == 0 && buffer->size > 0) {
212 // We've reached EOS but the audio track is not stopped yet,
213 // keep playing silence.
214 memset(buffer->raw, 0, buffer->size);
215 actualSize = buffer->size;
216 }
218 buffer->size = actualSize;
219 } break;
221 case AudioTrack::EVENT_STREAM_END:
222 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Callback wrapper: EVENT_STREAM_END"));
223 (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
224 me->mCallbackCookie, CB_EVENT_STREAM_END);
225 break;
227 case AudioTrack::EVENT_NEW_IAUDIOTRACK :
228 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Callback wrapper: EVENT_TEAR_DOWN"));
229 (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
230 me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
231 break;
233 default:
234 AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("received unknown event type: %d in"
235 " Callback wrapper!", aEvent));
236 break;
237 }
239 data->Unlock();
240 }
242 } // namespace mozilla