/*
**
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef ANDROID_AUDIO_OUTPUT_H
#define ANDROID_AUDIO_OUTPUT_H
#include <semaphore.h>
#include <tinyalsa/asoundlib.h>
#include <utils/LinearTransform.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Vector.h>
namespace android {
class AudioStreamOut;
class AudioOutput : public RefBase {
public:
// Audio ouput state machine states.
enum State {
// Ouput not yet started or synchronized.
OUT_OF_SYNC,
// Silence primed to output to start DMA.
PRIMED,
// DMA started, ready to align to other inputs.
DMA_START,
// DMA active.
ACTIVE,
// Fatal, unrecoverable error.
FATAL,
};
AudioOutput(const char* alsa_name,
enum pcm_format alsa_pcm_format);
virtual ~AudioOutput();
virtual status_t initCheck();
virtual status_t setupForStream(const AudioStreamOut& stream) = 0;
// State machine transition functions.
State getState() { return mState; };
bool hasFatalError() { return mState == FATAL; }
// Prime data to output device, go to PRIMED state.
void primeOutput(bool hasActiveOutputs);
// Adjust for write timestamp difference, go to ACTIVE state.
void adjustDelay(int32_t nFrames);
// Send one chunk of data to ALSA, if state machine permits. This is called
// for every chunk sent down, regardless of the state of the output.
void processOneChunk(const uint8_t* data, size_t len,
bool hasActiveOutputs, audio_format_t format);
status_t getNextWriteTimestamp(int64_t* timestamp,
bool* discon);
bool getLastNextWriteTSValid() const;
int64_t getLastNextWriteTS() const;
uint32_t getExternalDelay_uSec() const;
void setExternalDelay_uSec(uint32_t delay);
void setDelayComp_uSec(uint32_t delay_usec);
void setVolume(float vol);
void setMute(bool mute);
void setOutputIsFixed(bool fixed);
void setFixedOutputLevel(float level);
float getVolume() const { return mVolume; }
bool getMute() const { return mMute; }
bool getOutputIsFixed() const { return mOutputFixed; }
float getFixedOutputLevel() const { return mFixedLvl; }
int getHardwareTimestamp(unsigned int *pAvail,
struct timespec *pTimestamp);
uint32_t getKernelBufferSize() { return mFramesPerChunk * mBufferChunks; }
virtual void dump(String8& result) = 0;
virtual const char* getOutputName() = 0;
virtual uint32_t devMask() const = 0;
virtual void cleanupResources();
static const uint32_t kMaxDelayCompensationMSec;
static const uint32_t kPrimeTimeoutChunks;
protected:
void pushSilence(uint32_t nFrames);
virtual void openPCMDevice();
virtual void reset();
virtual status_t getDMAStartData(int64_t* dma_start_time,
int64_t* frames_queued_to_driver);
void doPCMWrite(const uint8_t* data, size_t len, audio_format_t format);
void setupInternal();
// Current state machine state.
State mState;
// Output format
uint32_t mFramesPerChunk;
uint32_t mFramesPerSec;
uint32_t mBufferChunks;
uint32_t mChannelCnt;
const char* mALSAName;
enum pcm_format mALSAFormat;
// These numbers are relative to the ALSA output.
uint32_t mBytesPerSample;
uint32_t mBytesPerFrame;
uint32_t mBytesPerChunk;
size_t mStagingSize;
void* mStagingBuf;
size_t mSilenceSize;
void* mSilenceBuf;
// Get next write time stuff.
bool mLastNextWriteTimeValid;
int64_t mLastNextWriteTime;
int64_t mLastDMAStartTime;
// External delay compensation.
uint32_t mMaxDelayCompFrames;
uint32_t mExternalDelayUSec;
uint32_t mExternalDelayLocalTicks;
LinearTransform mFramesToLocalTime;
// ALSA device stuff.
Mutex mDeviceLock;
struct pcm* mDevice;
int mDeviceExtFd;
int mALSACardID;
uint64_t mFramesQueuedToDriver;
uint32_t mPrimeTimeoutChunks;
// reduce log spew
bool mReportedWriteFail;
// Volume stuff
Mutex mVolumeLock;
float mVolume;
float mFixedLvl;
bool mMute;
bool mOutputFixed;
bool mVolParamsDirty;
virtual void applyPendingVolParams() = 0;
};
typedef Vector< sp<AudioOutput> > AudioOutputList;
} // namespace android
#endif // ANDROID_AUDIO_OUTPUT_H