2008-10-21 07:00:00 -07:00
/* //device/include/server/AudioFlinger/AudioFlinger.cpp
* *
* * Copyright 2007 , 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 .
*/
# define LOG_TAG "AudioFlinger"
2010-07-09 13:34:17 -07:00
//#define LOG_NDEBUG 0
2008-10-21 07:00:00 -07:00
# include <math.h>
# include <signal.h>
# include <sys/time.h>
# include <sys/resource.h>
2011-02-24 14:51:45 -08:00
# include <binder/IPCThreadState.h>
2009-05-19 19:08:10 -07:00
# include <binder/IServiceManager.h>
2008-10-21 07:00:00 -07:00
# include <utils/Log.h>
2009-05-19 19:08:10 -07:00
# include <binder/Parcel.h>
# include <binder/IPCThreadState.h>
2008-10-21 07:00:00 -07:00
# include <utils/String16.h>
# include <utils/threads.h>
2011-03-28 18:37:07 -07:00
# include <utils/Atomic.h>
2008-10-21 07:00:00 -07:00
2011-04-19 22:30:36 -07:00
# include <cutils/bitops.h>
2008-12-17 18:05:43 -08:00
# include <cutils/properties.h>
2008-10-21 07:00:00 -07:00
# include <media/AudioTrack.h>
# include <media/AudioRecord.h>
2011-02-24 14:51:45 -08:00
# include <media/IMediaPlayerService.h>
2008-10-21 07:00:00 -07:00
# include <private/media/AudioTrackShared.h>
2010-06-01 23:49:17 -07:00
# include <private/media/AudioEffectShared.h>
2011-04-19 22:30:36 -07:00
2011-05-11 14:15:23 -07:00
# include <system/audio.h>
2011-06-13 18:16:26 -07:00
# include <hardware/audio.h>
2008-10-21 07:00:00 -07:00
# include "AudioMixer.h"
# include "AudioFlinger.h"
2010-06-23 17:38:20 -07:00
# include <media/EffectsFactoryApi.h>
2011-06-24 07:01:31 -07:00
# include <audio_effects/effect_visualizer.h>
2011-08-01 09:52:20 -07:00
# include <audio_effects/effect_ns.h>
# include <audio_effects/effect_aec.h>
2010-06-01 23:49:17 -07:00
2011-07-08 15:26:12 -07:00
# include <cpustats/ThreadCpuUsage.h>
2011-07-22 09:04:31 -07:00
# include <powermanager/PowerManager.h>
2011-07-08 15:26:12 -07:00
// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
2009-03-03 19:31:44 -08:00
// ----------------------------------------------------------------------------
2010-07-13 04:45:46 -07:00
2008-10-21 07:00:00 -07:00
namespace android {
2009-03-18 17:39:46 -07:00
static const char * kDeadlockedString = " AudioFlinger may be deadlocked \n " ;
static const char * kHardwareLockedString = " Hardware lock is taken \n " ;
2008-12-17 18:05:43 -08:00
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
2008-10-21 07:00:00 -07:00
static const float MAX_GAIN = 4096.0f ;
2010-06-01 23:49:17 -07:00
static const float MAX_GAIN_INT = 0x1000 ;
2008-10-21 07:00:00 -07:00
// retry counts for buffer fill timeout
// 50 * ~20msecs = 1 second
static const int8_t kMaxTrackRetries = 50 ;
static const int8_t kMaxTrackStartupRetries = 50 ;
2010-03-11 14:47:00 -08:00
// allow less retry attempts on direct output thread.
// direct outputs can be a scarce resource in audio hardware and should
// be released as quickly as possible.
static const int8_t kMaxTrackRetriesDirect = 2 ;
2008-10-21 07:00:00 -07:00
2009-03-09 11:52:12 -07:00
static const int kDumpLockRetries = 50 ;
static const int kDumpLockSleep = 20000 ;
2009-09-30 03:09:03 -07:00
static const nsecs_t kWarningThrottle = seconds ( 5 ) ;
2011-06-17 21:29:58 -07:00
// RecordThread loop sleep time upon application overrun or audio HAL read error
static const int kRecordThreadSleepUs = 5000 ;
2009-03-03 19:31:44 -08:00
2011-09-13 11:40:21 -07:00
static const nsecs_t kSetParametersTimeout = seconds ( 2 ) ;
2008-10-21 07:00:00 -07:00
// ----------------------------------------------------------------------------
static bool recordingAllowed ( ) {
if ( getpid ( ) = = IPCThreadState : : self ( ) - > getCallingPid ( ) ) return true ;
bool ok = checkCallingPermission ( String16 ( " android.permission.RECORD_AUDIO " ) ) ;
if ( ! ok ) LOGE ( " Request requires android.permission.RECORD_AUDIO " ) ;
return ok ;
}
static bool settingsAllowed ( ) {
if ( getpid ( ) = = IPCThreadState : : self ( ) - > getCallingPid ( ) ) return true ;
bool ok = checkCallingPermission ( String16 ( " android.permission.MODIFY_AUDIO_SETTINGS " ) ) ;
if ( ! ok ) LOGE ( " Request requires android.permission.MODIFY_AUDIO_SETTINGS " ) ;
return ok ;
}
2011-02-24 14:51:45 -08:00
// To collect the amplifier usage
static void addBatteryData ( uint32_t params ) {
sp < IBinder > binder =
defaultServiceManager ( ) - > getService ( String16 ( " media.player " ) ) ;
sp < IMediaPlayerService > service = interface_cast < IMediaPlayerService > ( binder ) ;
if ( service . get ( ) = = NULL ) {
LOGW ( " Cannot connect to the MediaPlayerService for battery tracking " ) ;
return ;
}
service - > addBatteryData ( params ) ;
}
2011-04-18 16:57:27 -07:00
static int load_audio_interface ( const char * if_name , const hw_module_t * * mod ,
audio_hw_device_t * * dev )
{
int rc ;
rc = hw_get_module_by_class ( AUDIO_HARDWARE_MODULE_ID , if_name , mod ) ;
if ( rc )
goto out ;
rc = audio_hw_device_open ( * mod , dev ) ;
LOGE_IF ( rc , " couldn't open audio hw device in %s.%s (%s) " ,
AUDIO_HARDWARE_MODULE_ID , if_name , strerror ( - rc ) ) ;
if ( rc )
goto out ;
return 0 ;
out :
* mod = NULL ;
* dev = NULL ;
return rc ;
}
static const char * audio_interfaces [ ] = {
" primary " ,
" a2dp " ,
" usb " ,
} ;
# define ARRAY_SIZE(x) (sizeof((x)) / sizeof(((x)[0])))
2008-10-21 07:00:00 -07:00
// ----------------------------------------------------------------------------
AudioFlinger : : AudioFlinger ( )
2009-03-03 19:31:44 -08:00
: BnAudioFlinger ( ) ,
2011-08-01 09:52:20 -07:00
mPrimaryHardwareDev ( 0 ) , mMasterVolume ( 1.0f ) , mMasterMute ( false ) , mNextUniqueId ( 1 ) ,
2011-08-29 12:42:48 -07:00
mBtNrecIsOff ( false )
2011-04-19 19:04:32 -07:00
{
}
void AudioFlinger : : onFirstRef ( )
2008-10-21 07:00:00 -07:00
{
2011-04-18 16:57:27 -07:00
int rc = 0 ;
2011-04-19 22:30:36 -07:00
2011-01-18 18:39:02 -08:00
Mutex : : Autolock _l ( mLock ) ;
2011-04-18 16:57:27 -07:00
/* TODO: move all this work into an Init() function */
2008-10-21 07:00:00 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
2009-07-17 12:17:14 -07:00
2011-04-18 16:57:27 -07:00
for ( size_t i = 0 ; i < ARRAY_SIZE ( audio_interfaces ) ; i + + ) {
const hw_module_t * mod ;
audio_hw_device_t * dev ;
2011-04-19 22:30:36 -07:00
2011-04-18 16:57:27 -07:00
rc = load_audio_interface ( audio_interfaces [ i ] , & mod , & dev ) ;
if ( rc )
continue ;
LOGI ( " Loaded %s audio interface from %s (%s) " , audio_interfaces [ i ] ,
mod - > name , mod - > id ) ;
mAudioHwDevs . push ( dev ) ;
if ( ! mPrimaryHardwareDev ) {
mPrimaryHardwareDev = dev ;
LOGI ( " Using '%s' (%s.%s) as the primary audio interface " ,
2011-04-19 19:04:32 -07:00
mod - > name , mod - > id , audio_interfaces [ i ] ) ;
2011-04-18 16:57:27 -07:00
}
}
2009-07-17 12:17:14 -07:00
2008-10-21 07:00:00 -07:00
mHardwareStatus = AUDIO_HW_INIT ;
2011-04-19 22:30:36 -07:00
2011-04-18 16:57:27 -07:00
if ( ! mPrimaryHardwareDev | | mAudioHwDevs . size ( ) = = 0 ) {
LOGE ( " Primary audio interface not found " ) ;
return ;
}
for ( size_t i = 0 ; i < mAudioHwDevs . size ( ) ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
mHardwareStatus = AUDIO_HW_INIT ;
rc = dev - > init_check ( dev ) ;
if ( rc = = 0 ) {
AutoMutex lock ( mHardwareLock ) ;
mMode = AUDIO_MODE_NORMAL ;
mHardwareStatus = AUDIO_HW_SET_MODE ;
dev - > set_mode ( dev , mMode ) ;
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME ;
dev - > set_master_volume ( dev , 1.0f ) ;
mHardwareStatus = AUDIO_HW_IDLE ;
}
2008-10-21 07:00:00 -07:00
}
}
2011-04-19 19:04:32 -07:00
status_t AudioFlinger : : initCheck ( ) const
{
Mutex : : Autolock _l ( mLock ) ;
if ( mPrimaryHardwareDev = = NULL | | mAudioHwDevs . size ( ) = = 0 )
return NO_INIT ;
return NO_ERROR ;
}
2008-10-21 07:00:00 -07:00
AudioFlinger : : ~ AudioFlinger ( )
{
2011-04-18 16:57:27 -07:00
int num_devs = mAudioHwDevs . size ( ) ;
2009-08-28 10:39:03 -07:00
while ( ! mRecordThreads . isEmpty ( ) ) {
// closeInput() will remove first entry from mRecordThreads
closeInput ( mRecordThreads . keyAt ( 0 ) ) ;
}
while ( ! mPlaybackThreads . isEmpty ( ) ) {
// closeOutput() will remove first entry from mPlaybackThreads
closeOutput ( mPlaybackThreads . keyAt ( 0 ) ) ;
}
2011-04-18 16:57:27 -07:00
for ( int i = 0 ; i < num_devs ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
audio_hw_device_close ( dev ) ;
2009-08-28 10:39:03 -07:00
}
2011-04-18 16:57:27 -07:00
mAudioHwDevs . clear ( ) ;
2008-12-17 18:05:43 -08:00
}
2011-04-18 16:57:27 -07:00
audio_hw_device_t * AudioFlinger : : findSuitableHwDev_l ( uint32_t devices )
{
/* first matching HW device is returned */
for ( size_t i = 0 ; i < mAudioHwDevs . size ( ) ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
if ( ( dev - > get_supported_devices ( dev ) & devices ) = = devices )
return dev ;
}
return NULL ;
}
2009-01-22 00:13:42 -08:00
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : dumpClients ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
result . append ( " Clients: \n " ) ;
for ( size_t i = 0 ; i < mClients . size ( ) ; + + i ) {
wp < Client > wClient = mClients . valueAt ( i ) ;
if ( wClient ! = 0 ) {
sp < Client > client = wClient . promote ( ) ;
if ( client ! = 0 ) {
snprintf ( buffer , SIZE , " pid: %d \n " , client - > pid ( ) ) ;
result . append ( buffer ) ;
}
}
}
2011-08-02 13:33:41 -07:00
result . append ( " Global session refs: \n " ) ;
result . append ( " session pid cnt \n " ) ;
for ( size_t i = 0 ; i < mAudioSessionRefs . size ( ) ; i + + ) {
AudioSessionRef * r = mAudioSessionRefs [ i ] ;
snprintf ( buffer , SIZE , " %7d %3d %3d \n " , r - > sessionid , r - > pid , r - > cnt ) ;
result . append ( buffer ) ;
}
2008-10-21 07:00:00 -07:00
write ( fd , result . string ( ) , result . size ( ) ) ;
return NO_ERROR ;
}
status_t AudioFlinger : : dumpInternals ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
2009-03-09 11:52:12 -07:00
int hardwareStatus = mHardwareStatus ;
2009-07-17 12:17:14 -07:00
2009-03-09 11:52:12 -07:00
snprintf ( buffer , SIZE , " Hardware status: %d \n " , hardwareStatus ) ;
2008-10-21 07:00:00 -07:00
result . append ( buffer ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
return NO_ERROR ;
}
status_t AudioFlinger : : dumpPermissionDenial ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
snprintf ( buffer , SIZE , " Permission Denial: "
" can't dump AudioFlinger from pid=%d, uid=%d \n " ,
IPCThreadState : : self ( ) - > getCallingPid ( ) ,
IPCThreadState : : self ( ) - > getCallingUid ( ) ) ;
result . append ( buffer ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
return NO_ERROR ;
}
2009-03-18 17:39:46 -07:00
static bool tryLock ( Mutex & mutex )
{
bool locked = false ;
for ( int i = 0 ; i < kDumpLockRetries ; + + i ) {
if ( mutex . tryLock ( ) = = NO_ERROR ) {
locked = true ;
break ;
}
usleep ( kDumpLockSleep ) ;
}
return locked ;
}
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : dump ( int fd , const Vector < String16 > & args )
{
if ( checkCallingPermission ( String16 ( " android.permission.DUMP " ) ) = = false ) {
dumpPermissionDenial ( fd , args ) ;
} else {
2009-03-18 17:39:46 -07:00
// get state of hardware lock
bool hardwareLocked = tryLock ( mHardwareLock ) ;
if ( ! hardwareLocked ) {
String8 result ( kHardwareLockedString ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
} else {
mHardwareLock . unlock ( ) ;
}
bool locked = tryLock ( mLock ) ;
// failed to lock - AudioFlinger is probably deadlocked
if ( ! locked ) {
String8 result ( kDeadlockedString ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
2009-03-09 11:52:12 -07:00
}
2008-10-21 07:00:00 -07:00
dumpClients ( fd , args ) ;
dumpInternals ( fd , args ) ;
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
// dump playback threads
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
2009-07-28 08:44:33 -07:00
mPlaybackThreads . valueAt ( i ) - > dump ( fd , args ) ;
2009-07-17 12:17:14 -07:00
}
// dump record threads
2009-07-23 13:35:01 -07:00
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
2009-07-28 08:44:33 -07:00
mRecordThreads . valueAt ( i ) - > dump ( fd , args ) ;
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
2011-04-18 16:57:27 -07:00
// dump all hardware devs
for ( size_t i = 0 ; i < mAudioHwDevs . size ( ) ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
dev - > dump ( dev , fd ) ;
2008-10-21 07:00:00 -07:00
}
2009-03-09 11:52:12 -07:00
if ( locked ) mLock . unlock ( ) ;
2008-10-21 07:00:00 -07:00
}
return NO_ERROR ;
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
// IAudioFlinger interface
2008-10-21 07:00:00 -07:00
2009-03-03 19:31:44 -08:00
sp < IAudioTrack > AudioFlinger : : createTrack (
pid_t pid ,
int streamType ,
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2009-03-03 19:31:44 -08:00
int frameCount ,
uint32_t flags ,
const sp < IMemory > & sharedBuffer ,
2009-07-28 08:44:33 -07:00
int output ,
2010-06-01 23:49:17 -07:00
int * sessionId ,
2009-03-03 19:31:44 -08:00
status_t * status )
{
2009-07-17 12:17:14 -07:00
sp < PlaybackThread : : Track > track ;
2009-03-03 19:31:44 -08:00
sp < TrackHandle > trackHandle ;
sp < Client > client ;
wp < Client > wclient ;
status_t lStatus ;
2010-06-01 23:49:17 -07:00
int lSessionId ;
2008-10-21 07:00:00 -07:00
2011-04-19 22:30:36 -07:00
if ( streamType > = AUDIO_STREAM_CNT ) {
2009-03-03 19:31:44 -08:00
LOGE ( " invalid stream type " ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
2009-01-09 17:51:23 -08:00
2009-03-03 19:31:44 -08:00
{
Mutex : : Autolock _l ( mLock ) ;
2009-07-17 12:17:14 -07:00
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
2010-07-28 01:32:47 -07:00
PlaybackThread * effectThread = NULL ;
2009-07-17 12:17:14 -07:00
if ( thread = = NULL ) {
LOGE ( " unknown output thread " ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
2009-01-09 17:51:23 -08:00
2009-03-03 19:31:44 -08:00
wclient = mClients . valueFor ( pid ) ;
2009-01-09 17:51:23 -08:00
2009-03-03 19:31:44 -08:00
if ( wclient ! = NULL ) {
client = wclient . promote ( ) ;
} else {
client = new Client ( this , pid ) ;
mClients . add ( pid , client ) ;
}
2010-06-01 23:49:17 -07:00
LOGV ( " createTrack() sessionId: %d " , ( sessionId = = NULL ) ? - 2 : * sessionId ) ;
2011-04-19 22:30:36 -07:00
if ( sessionId ! = NULL & & * sessionId ! = AUDIO_SESSION_OUTPUT_MIX ) {
2010-07-13 04:45:46 -07:00
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
2010-07-28 01:32:47 -07:00
sp < PlaybackThread > t = mPlaybackThreads . valueAt ( i ) ;
if ( mPlaybackThreads . keyAt ( i ) ! = output ) {
// prevent same audio session on different output threads
uint32_t sessions = t - > hasAudioSession ( * sessionId ) ;
if ( sessions & PlaybackThread : : TRACK_SESSION ) {
lStatus = BAD_VALUE ;
goto Exit ;
}
// check if an effect with same session ID is waiting for a track to be created
if ( sessions & PlaybackThread : : EFFECT_SESSION ) {
effectThread = t . get ( ) ;
}
2010-07-13 04:45:46 -07:00
}
}
2010-06-01 23:49:17 -07:00
lSessionId = * sessionId ;
} else {
2010-07-13 04:45:46 -07:00
// if no audio session id is provided, create one here
2011-06-17 21:29:58 -07:00
lSessionId = nextUniqueId ( ) ;
2010-06-01 23:49:17 -07:00
if ( sessionId ! = NULL ) {
* sessionId = lSessionId ;
}
}
LOGV ( " createTrack() lSessionId: %d " , lSessionId ) ;
2009-07-17 12:17:14 -07:00
track = thread - > createTrack_l ( client , streamType , sampleRate , format ,
2011-05-24 15:53:33 -07:00
channelMask , frameCount , sharedBuffer , lSessionId , & lStatus ) ;
2010-07-28 01:32:47 -07:00
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
if ( lStatus = = NO_ERROR & & effectThread ! = NULL ) {
Mutex : : Autolock _dl ( thread - > mLock ) ;
Mutex : : Autolock _sl ( effectThread - > mLock ) ;
moveEffectChain_l ( lSessionId , effectThread , thread , true ) ;
}
2009-03-09 11:52:12 -07:00
}
if ( lStatus = = NO_ERROR ) {
trackHandle = new TrackHandle ( track ) ;
} else {
2009-09-17 05:12:56 -07:00
// remove local strong reference to Client before deleting the Track so that the Client
// destructor is called by the TrackBase destructor with mLock held
client . clear ( ) ;
2009-03-09 11:52:12 -07:00
track . clear ( ) ;
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
2009-03-03 19:31:44 -08:00
Exit :
if ( status ) {
* status = lStatus ;
}
return trackHandle ;
}
2008-10-21 07:00:00 -07:00
2009-07-28 08:44:33 -07:00
uint32_t AudioFlinger : : sampleRate ( int output ) const
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " sampleRate() unknown thread %d " , output ) ;
2009-07-17 12:17:14 -07:00
return 0 ;
}
return thread - > sampleRate ( ) ;
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
2009-07-28 08:44:33 -07:00
int AudioFlinger : : channelCount ( int output ) const
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " channelCount() unknown thread %d " , output ) ;
2009-07-17 12:17:14 -07:00
return 0 ;
}
return thread - > channelCount ( ) ;
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
2011-05-24 15:53:33 -07:00
uint32_t AudioFlinger : : format ( int output ) const
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " format() unknown thread %d " , output ) ;
2009-07-17 12:17:14 -07:00
return 0 ;
}
return thread - > format ( ) ;
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
2009-07-28 08:44:33 -07:00
size_t AudioFlinger : : frameCount ( int output ) const
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " frameCount() unknown thread %d " , output ) ;
2009-07-17 12:17:14 -07:00
return 0 ;
}
return thread - > frameCount ( ) ;
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
2009-07-28 08:44:33 -07:00
uint32_t AudioFlinger : : latency ( int output ) const
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " latency() unknown thread %d " , output ) ;
2009-07-17 12:17:14 -07:00
return 0 ;
}
return thread - > latency ( ) ;
2008-12-17 18:05:43 -08:00
}
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : setMasterVolume ( float value )
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return ret ;
}
2008-10-21 07:00:00 -07:00
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
// when hw supports master volume, don't scale in sw mixer
2011-01-18 18:39:02 -08:00
{ // scope for the lock
AutoMutex lock ( mHardwareLock ) ;
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME ;
2011-04-18 16:57:27 -07:00
if ( mPrimaryHardwareDev - > set_master_volume ( mPrimaryHardwareDev , value ) = = NO_ERROR ) {
2011-01-18 18:39:02 -08:00
value = 1.0f ;
}
mHardwareStatus = AUDIO_HW_IDLE ;
2008-10-21 07:00:00 -07:00
}
2008-12-17 18:05:43 -08:00
2011-01-18 18:39:02 -08:00
Mutex : : Autolock _l ( mLock ) ;
2009-07-17 12:17:14 -07:00
mMasterVolume = value ;
for ( uint32_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + )
2009-07-28 08:44:33 -07:00
mPlaybackThreads . valueAt ( i ) - > setMasterVolume ( value ) ;
2008-10-21 07:00:00 -07:00
2009-07-17 12:17:14 -07:00
return NO_ERROR ;
2008-10-21 07:00:00 -07:00
}
status_t AudioFlinger : : setMode ( int mode )
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return ret ;
}
2010-06-23 17:38:20 -07:00
2008-10-21 07:00:00 -07:00
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
2011-04-19 22:30:36 -07:00
if ( ( mode < 0 ) | | ( mode > = AUDIO_MODE_CNT ) ) {
2008-10-21 07:00:00 -07:00
LOGW ( " Illegal value: setMode(%d) " , mode ) ;
return BAD_VALUE ;
}
2010-06-23 17:38:20 -07:00
{ // scope for the lock
AutoMutex lock ( mHardwareLock ) ;
mHardwareStatus = AUDIO_HW_SET_MODE ;
2011-04-18 16:57:27 -07:00
ret = mPrimaryHardwareDev - > set_mode ( mPrimaryHardwareDev , mode ) ;
2010-06-23 17:38:20 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
}
2010-03-05 12:18:01 -08:00
if ( NO_ERROR = = ret ) {
2010-06-23 17:38:20 -07:00
Mutex : : Autolock _l ( mLock ) ;
mMode = mode ;
for ( uint32_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + )
mPlaybackThreads . valueAt ( i ) - > setMode ( mode ) ;
}
2008-10-21 07:00:00 -07:00
return ret ;
}
status_t AudioFlinger : : setMicMute ( bool state )
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return ret ;
}
2008-10-21 07:00:00 -07:00
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
AutoMutex lock ( mHardwareLock ) ;
mHardwareStatus = AUDIO_HW_SET_MIC_MUTE ;
2011-08-23 08:25:03 -07:00
ret = mPrimaryHardwareDev - > set_mic_mute ( mPrimaryHardwareDev , state ) ;
2008-10-21 07:00:00 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
return ret ;
}
bool AudioFlinger : : getMicMute ( ) const
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return false ;
}
2011-04-19 22:30:36 -07:00
bool state = AUDIO_MODE_INVALID ;
2008-10-21 07:00:00 -07:00
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE ;
2011-04-18 16:57:27 -07:00
mPrimaryHardwareDev - > get_mic_mute ( mPrimaryHardwareDev , & state ) ;
2008-10-21 07:00:00 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
return state ;
}
status_t AudioFlinger : : setMasterMute ( bool muted )
{
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
2009-07-17 12:17:14 -07:00
2011-01-18 18:39:02 -08:00
Mutex : : Autolock _l ( mLock ) ;
2009-07-17 12:17:14 -07:00
mMasterMute = muted ;
for ( uint32_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + )
2009-07-28 08:44:33 -07:00
mPlaybackThreads . valueAt ( i ) - > setMasterMute ( muted ) ;
2009-07-17 12:17:14 -07:00
2008-10-21 07:00:00 -07:00
return NO_ERROR ;
}
float AudioFlinger : : masterVolume ( ) const
{
2009-07-17 12:17:14 -07:00
return mMasterVolume ;
2008-10-21 07:00:00 -07:00
}
bool AudioFlinger : : masterMute ( ) const
{
2009-07-17 12:17:14 -07:00
return mMasterMute ;
2008-10-21 07:00:00 -07:00
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : setStreamVolume ( int stream , float value , int output )
2008-10-21 07:00:00 -07:00
{
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
2011-04-19 22:30:36 -07:00
if ( stream < 0 | | uint32_t ( stream ) > = AUDIO_STREAM_CNT ) {
2008-10-21 07:00:00 -07:00
return BAD_VALUE ;
}
2008-12-17 18:05:43 -08:00
2009-07-17 12:17:14 -07:00
AutoMutex lock ( mLock ) ;
PlaybackThread * thread = NULL ;
if ( output ) {
thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
return BAD_VALUE ;
}
}
mStreamTypes [ stream ] . volume = value ;
if ( thread = = NULL ) {
2009-10-21 08:14:22 -07:00
for ( uint32_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
2009-07-28 08:44:33 -07:00
mPlaybackThreads . valueAt ( i ) - > setStreamVolume ( stream , value ) ;
2009-10-21 08:14:22 -07:00
}
2009-07-17 12:17:14 -07:00
} else {
thread - > setStreamVolume ( stream , value ) ;
}
2009-03-03 19:31:44 -08:00
2009-10-21 08:14:22 -07:00
return NO_ERROR ;
2008-10-21 07:00:00 -07:00
}
status_t AudioFlinger : : setStreamMute ( int stream , bool muted )
{
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
2011-04-19 22:30:36 -07:00
if ( stream < 0 | | uint32_t ( stream ) > = AUDIO_STREAM_CNT | |
uint32_t ( stream ) = = AUDIO_STREAM_ENFORCED_AUDIBLE ) {
2008-10-21 07:00:00 -07:00
return BAD_VALUE ;
}
2009-03-18 17:39:46 -07:00
2011-01-18 18:39:02 -08:00
AutoMutex lock ( mLock ) ;
2009-07-17 12:17:14 -07:00
mStreamTypes [ stream ] . mute = muted ;
for ( uint32_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + )
2009-07-28 08:44:33 -07:00
mPlaybackThreads . valueAt ( i ) - > setStreamMute ( stream , muted ) ;
2009-03-03 19:31:44 -08:00
2008-10-21 07:00:00 -07:00
return NO_ERROR ;
}
2009-07-28 08:44:33 -07:00
float AudioFlinger : : streamVolume ( int stream , int output ) const
2008-10-21 07:00:00 -07:00
{
2011-04-19 22:30:36 -07:00
if ( stream < 0 | | uint32_t ( stream ) > = AUDIO_STREAM_CNT ) {
2008-10-21 07:00:00 -07:00
return 0.0f ;
}
2009-07-17 12:17:14 -07:00
AutoMutex lock ( mLock ) ;
float volume ;
if ( output ) {
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
return 0.0f ;
}
volume = thread - > streamVolume ( stream ) ;
} else {
volume = mStreamTypes [ stream ] . volume ;
}
2009-04-21 07:56:33 -07:00
return volume ;
2008-10-21 07:00:00 -07:00
}
bool AudioFlinger : : streamMute ( int stream ) const
{
2011-04-19 22:30:36 -07:00
if ( stream < 0 | | stream > = ( int ) AUDIO_STREAM_CNT ) {
2008-10-21 07:00:00 -07:00
return true ;
}
2009-07-17 12:17:14 -07:00
return mStreamTypes [ stream ] . mute ;
2008-10-21 07:00:00 -07:00
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : setParameters ( int ioHandle , const String8 & keyValuePairs )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
status_t result ;
2009-07-28 08:44:33 -07:00
LOGV ( " setParameters(): io %d, keyvalue %s, tid %d, calling tid %d " ,
2009-07-17 12:17:14 -07:00
ioHandle , keyValuePairs . string ( ) , gettid ( ) , IPCThreadState : : self ( ) - > getCallingPid ( ) ) ;
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
2009-01-15 16:12:10 -08:00
}
2009-07-17 12:17:14 -07:00
// ioHandle == 0 means the parameters are global to the audio hardware interface
if ( ioHandle = = 0 ) {
AutoMutex lock ( mHardwareLock ) ;
mHardwareStatus = AUDIO_SET_PARAMETER ;
2011-04-18 16:57:27 -07:00
status_t final_result = NO_ERROR ;
for ( size_t i = 0 ; i < mAudioHwDevs . size ( ) ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
result = dev - > set_parameters ( dev , keyValuePairs . string ( ) ) ;
final_result = result ? : final_result ;
}
2009-07-17 12:17:14 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
2011-08-01 09:52:20 -07:00
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
AudioParameter param = AudioParameter ( keyValuePairs ) ;
String8 value ;
if ( param . get ( String8 ( AUDIO_PARAMETER_KEY_BT_NREC ) , value ) = = NO_ERROR ) {
Mutex : : Autolock _l ( mLock ) ;
2011-08-29 12:42:48 -07:00
bool btNrecIsOff = ( value = = AUDIO_PARAMETER_VALUE_OFF ) ;
if ( mBtNrecIsOff ! = btNrecIsOff ) {
2011-08-01 09:52:20 -07:00
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
sp < RecordThread > thread = mRecordThreads . valueAt ( i ) ;
RecordThread : : RecordTrack * track = thread - > track ( ) ;
if ( track ! = NULL ) {
audio_devices_t device = ( audio_devices_t ) (
thread - > device ( ) & AUDIO_DEVICE_IN_ALL ) ;
2011-08-29 12:42:48 -07:00
bool suspend = audio_is_bluetooth_sco_device ( device ) & & btNrecIsOff ;
2011-08-01 09:52:20 -07:00
thread - > setEffectSuspended ( FX_IID_AEC ,
suspend ,
track - > sessionId ( ) ) ;
thread - > setEffectSuspended ( FX_IID_NS ,
suspend ,
track - > sessionId ( ) ) ;
}
}
2011-08-29 12:42:48 -07:00
mBtNrecIsOff = btNrecIsOff ;
2011-08-01 09:52:20 -07:00
}
}
2011-04-18 16:57:27 -07:00
return final_result ;
2009-07-17 12:17:14 -07:00
}
2009-09-29 11:12:57 -07:00
// hold a strong ref on thread in case closeOutput() or closeInput() is called
// and the thread is exited once the lock is released
sp < ThreadBase > thread ;
{
Mutex : : Autolock _l ( mLock ) ;
thread = checkPlaybackThread_l ( ioHandle ) ;
if ( thread = = NULL ) {
thread = checkRecordThread_l ( ioHandle ) ;
2011-06-17 21:29:58 -07:00
} else if ( thread . get ( ) = = primaryPlaybackThread_l ( ) ) {
// indicate output device change to all input threads for pre processing
AudioParameter param = AudioParameter ( keyValuePairs ) ;
int value ;
if ( param . getInt ( String8 ( AudioParameter : : keyRouting ) , value ) = = NO_ERROR ) {
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
mRecordThreads . valueAt ( i ) - > setParameters ( keyValuePairs ) ;
}
}
2009-09-29 11:12:57 -07:00
}
2009-07-17 12:17:14 -07:00
}
2009-09-29 11:12:57 -07:00
if ( thread ! = NULL ) {
2010-03-05 12:18:01 -08:00
result = thread - > setParameters ( keyValuePairs ) ;
return result ;
2009-07-17 12:17:14 -07:00
}
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
String8 AudioFlinger : : getParameters ( int ioHandle , const String8 & keys )
2009-07-17 12:17:14 -07:00
{
2009-07-28 08:44:33 -07:00
// LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
2009-07-17 12:17:14 -07:00
// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
if ( ioHandle = = 0 ) {
2011-04-19 22:30:36 -07:00
String8 out_s8 ;
2011-04-18 16:57:27 -07:00
for ( size_t i = 0 ; i < mAudioHwDevs . size ( ) ; i + + ) {
audio_hw_device_t * dev = mAudioHwDevs [ i ] ;
char * s = dev - > get_parameters ( dev , keys . string ( ) ) ;
out_s8 + = String8 ( s ) ;
free ( s ) ;
}
2011-04-19 22:30:36 -07:00
return out_s8 ;
2009-07-17 12:17:14 -07:00
}
2009-09-29 11:12:57 -07:00
Mutex : : Autolock _l ( mLock ) ;
2009-07-17 12:17:14 -07:00
PlaybackThread * playbackThread = checkPlaybackThread_l ( ioHandle ) ;
if ( playbackThread ! = NULL ) {
return playbackThread - > getParameters ( keys ) ;
}
RecordThread * recordThread = checkRecordThread_l ( ioHandle ) ;
if ( recordThread ! = NULL ) {
return recordThread - > getParameters ( keys ) ;
}
return String8 ( " " ) ;
2008-10-21 07:00:00 -07:00
}
2009-03-03 19:31:44 -08:00
size_t AudioFlinger : : getInputBufferSize ( uint32_t sampleRate , int format , int channelCount )
2008-10-21 07:00:00 -07:00
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return 0 ;
}
2011-04-18 16:57:27 -07:00
return mPrimaryHardwareDev - > get_input_buffer_size ( mPrimaryHardwareDev , sampleRate , format , channelCount ) ;
2008-10-21 07:00:00 -07:00
}
2010-02-26 02:47:27 -08:00
unsigned int AudioFlinger : : getInputFramesLost ( int ioHandle )
{
if ( ioHandle = = 0 ) {
return 0 ;
}
Mutex : : Autolock _l ( mLock ) ;
RecordThread * recordThread = checkRecordThread_l ( ioHandle ) ;
if ( recordThread ! = NULL ) {
return recordThread - > getInputFramesLost ( ) ;
}
return 0 ;
}
2009-10-21 08:14:22 -07:00
status_t AudioFlinger : : setVoiceVolume ( float value )
{
2011-08-23 08:25:03 -07:00
status_t ret = initCheck ( ) ;
if ( ret ! = NO_ERROR ) {
return ret ;
}
2009-10-21 08:14:22 -07:00
// check calling permissions
if ( ! settingsAllowed ( ) ) {
return PERMISSION_DENIED ;
}
AutoMutex lock ( mHardwareLock ) ;
mHardwareStatus = AUDIO_SET_VOICE_VOLUME ;
2011-08-23 08:25:03 -07:00
ret = mPrimaryHardwareDev - > set_voice_volume ( mPrimaryHardwareDev , value ) ;
2009-10-21 08:14:22 -07:00
mHardwareStatus = AUDIO_HW_IDLE ;
return ret ;
}
2010-01-19 17:37:09 -08:00
status_t AudioFlinger : : getRenderPosition ( uint32_t * halFrames , uint32_t * dspFrames , int output )
{
status_t status ;
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * playbackThread = checkPlaybackThread_l ( output ) ;
if ( playbackThread ! = NULL ) {
return playbackThread - > getRenderPosition ( halFrames , dspFrames ) ;
}
return BAD_VALUE ;
}
2009-03-03 19:31:44 -08:00
void AudioFlinger : : registerClient ( const sp < IAudioFlingerClient > & client )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
2008-10-21 07:00:00 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-05-12 02:05:53 -07:00
int pid = IPCThreadState : : self ( ) - > getCallingPid ( ) ;
if ( mNotificationClients . indexOfKey ( pid ) < 0 ) {
sp < NotificationClient > notificationClient = new NotificationClient ( this ,
client ,
pid ) ;
LOGV ( " registerClient() client %p, pid %d " , notificationClient . get ( ) , pid ) ;
2009-07-17 12:17:14 -07:00
2010-05-12 02:05:53 -07:00
mNotificationClients . add ( pid , notificationClient ) ;
2009-07-17 12:17:14 -07:00
2010-05-12 02:05:53 -07:00
sp < IBinder > binder = client - > asBinder ( ) ;
binder - > linkToDeath ( notificationClient ) ;
// the config change is always sent from playback or record threads to avoid deadlock
// with AudioSystem::gLock
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
mPlaybackThreads . valueAt ( i ) - > sendConfigEvent ( AudioSystem : : OUTPUT_OPENED ) ;
}
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
mRecordThreads . valueAt ( i ) - > sendConfigEvent ( AudioSystem : : INPUT_OPENED ) ;
}
2008-10-21 07:00:00 -07:00
}
}
2010-05-12 02:05:53 -07:00
void AudioFlinger : : removeNotificationClient ( pid_t pid )
{
2008-10-21 07:00:00 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-05-12 02:05:53 -07:00
int index = mNotificationClients . indexOfKey ( pid ) ;
if ( index > = 0 ) {
sp < NotificationClient > client = mNotificationClients . valueFor ( pid ) ;
LOGV ( " removeNotificationClient() %p, pid %d " , client . get ( ) , pid ) ;
mNotificationClients . removeItem ( pid ) ;
2008-10-21 07:00:00 -07:00
}
2011-08-02 13:33:41 -07:00
LOGV ( " %d died, releasing its sessions " , pid ) ;
int num = mAudioSessionRefs . size ( ) ;
bool removed = false ;
for ( int i = 0 ; i < num ; i + + ) {
AudioSessionRef * ref = mAudioSessionRefs . itemAt ( i ) ;
LOGV ( " pid %d @ %d " , ref - > pid , i ) ;
if ( ref - > pid = = pid ) {
LOGV ( " removing entry for pid %d session %d " , pid , ref - > sessionid ) ;
mAudioSessionRefs . removeAt ( i ) ;
delete ref ;
removed = true ;
i - - ;
num - - ;
}
}
if ( removed ) {
purgeStaleEffects_l ( ) ;
}
2008-10-21 07:00:00 -07:00
}
2009-09-15 07:10:12 -07:00
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
2010-05-12 02:05:53 -07:00
void AudioFlinger : : audioConfigChanged_l ( int event , int ioHandle , void * param2 )
{
2009-11-19 09:00:56 -08:00
size_t size = mNotificationClients . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
2010-05-12 02:05:53 -07:00
mNotificationClients . valueAt ( i ) - > client ( ) - > ioConfigChanged ( event , ioHandle , param2 ) ;
2009-07-17 12:17:14 -07:00
}
}
2009-09-17 05:12:56 -07:00
// removeClient_l() must be called with AudioFlinger::mLock held
void AudioFlinger : : removeClient_l ( pid_t pid )
2008-10-21 07:00:00 -07:00
{
2009-09-17 05:12:56 -07:00
LOGV ( " removeClient_l() pid %d, tid %d, calling tid %d " , pid , gettid ( ) , IPCThreadState : : self ( ) - > getCallingPid ( ) ) ;
2009-03-03 19:31:44 -08:00
mClients . removeItem ( pid ) ;
2008-10-21 07:00:00 -07:00
}
2010-05-12 02:05:53 -07:00
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2009-03-03 19:31:44 -08:00
2011-06-17 21:29:58 -07:00
AudioFlinger : : ThreadBase : : ThreadBase ( const sp < AudioFlinger > & audioFlinger , int id , uint32_t device )
2009-07-17 12:17:14 -07:00
: Thread ( false ) ,
mAudioFlinger ( audioFlinger ) , mSampleRate ( 0 ) , mFrameCount ( 0 ) , mChannelCount ( 0 ) ,
2011-07-22 09:04:31 -07:00
mFrameSize ( 1 ) , mFormat ( 0 ) , mStandby ( false ) , mId ( id ) , mExiting ( false ) ,
mDevice ( device )
2009-03-03 19:31:44 -08:00
{
2011-07-22 09:04:31 -07:00
mDeathRecipient = new PMDeathRecipient ( this ) ;
2009-03-03 19:31:44 -08:00
}
2009-01-22 00:13:42 -08:00
2009-07-17 12:17:14 -07:00
AudioFlinger : : ThreadBase : : ~ ThreadBase ( )
{
2009-08-04 09:45:33 -07:00
mParamCond . broadcast ( ) ;
mNewParameters . clear ( ) ;
2011-07-22 09:04:31 -07:00
// do not lock the mutex in destructor
releaseWakeLock_l ( ) ;
2011-09-27 12:07:15 -07:00
if ( mPowerManager ! = 0 ) {
sp < IBinder > binder = mPowerManager - > asBinder ( ) ;
binder - > unlinkToDeath ( mDeathRecipient ) ;
}
2009-03-11 12:11:56 -07:00
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
void AudioFlinger : : ThreadBase : : exit ( )
2009-03-03 19:31:44 -08:00
{
2009-09-29 11:12:57 -07:00
// keep a strong ref on ourself so that we wont get
2009-07-17 12:17:14 -07:00
// destroyed in the middle of requestExitAndWait()
sp < ThreadBase > strongMe = this ;
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
LOGV ( " ThreadBase::exit " ) ;
{
AutoMutex lock ( & mLock ) ;
2009-11-19 09:00:56 -08:00
mExiting = true ;
2009-07-17 12:17:14 -07:00
requestExit ( ) ;
mWaitWorkCV . signal ( ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
requestExitAndWait ( ) ;
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
uint32_t AudioFlinger : : ThreadBase : : sampleRate ( ) const
{
return mSampleRate ;
2009-01-22 00:13:42 -08:00
}
2009-07-17 12:17:14 -07:00
int AudioFlinger : : ThreadBase : : channelCount ( ) const
2009-01-22 00:13:42 -08:00
{
2010-05-14 05:45:46 -07:00
return ( int ) mChannelCount ;
2009-03-03 19:31:44 -08:00
}
2011-05-24 15:53:33 -07:00
uint32_t AudioFlinger : : ThreadBase : : format ( ) const
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
return mFormat ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
size_t AudioFlinger : : ThreadBase : : frameCount ( ) const
{
return mFrameCount ;
}
status_t AudioFlinger : : ThreadBase : : setParameters ( const String8 & keyValuePairs )
{
2009-08-04 09:45:33 -07:00
status_t status ;
2009-07-17 12:17:14 -07:00
2009-08-04 09:45:33 -07:00
LOGV ( " ThreadBase::setParameters() %s " , keyValuePairs . string ( ) ) ;
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
2009-08-04 09:45:33 -07:00
mNewParameters . add ( keyValuePairs ) ;
2009-07-17 12:17:14 -07:00
mWaitWorkCV . signal ( ) ;
2009-09-29 11:12:57 -07:00
// wait condition with timeout in case the thread loop has exited
// before the request could be processed
2011-09-13 11:40:21 -07:00
if ( mParamCond . waitRelative ( mLock , kSetParametersTimeout ) = = NO_ERROR ) {
2009-09-29 11:12:57 -07:00
status = mParamStatus ;
mWaitWorkCV . signal ( ) ;
} else {
status = TIMED_OUT ;
}
2009-08-04 09:45:33 -07:00
return status ;
2009-07-17 12:17:14 -07:00
}
void AudioFlinger : : ThreadBase : : sendConfigEvent ( int event , int param )
{
Mutex : : Autolock _l ( mLock ) ;
2009-08-04 09:45:33 -07:00
sendConfigEvent_l ( event , param ) ;
}
// sendConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger : : ThreadBase : : sendConfigEvent_l ( int event , int param )
{
2009-07-17 12:17:14 -07:00
ConfigEvent * configEvent = new ConfigEvent ( ) ;
configEvent - > mEvent = event ;
configEvent - > mParam = param ;
mConfigEvents . add ( configEvent ) ;
LOGV ( " sendConfigEvent() num events %d event %d, param %d " , mConfigEvents . size ( ) , event , param ) ;
mWaitWorkCV . signal ( ) ;
}
void AudioFlinger : : ThreadBase : : processConfigEvents ( )
{
mLock . lock ( ) ;
while ( ! mConfigEvents . isEmpty ( ) ) {
LOGV ( " processConfigEvents() remaining events %d " , mConfigEvents . size ( ) ) ;
ConfigEvent * configEvent = mConfigEvents [ 0 ] ;
mConfigEvents . removeAt ( 0 ) ;
2010-05-14 03:26:45 -07:00
// release mLock before locking AudioFlinger mLock: lock order is always
// AudioFlinger then ThreadBase to avoid cross deadlock
2009-07-17 12:17:14 -07:00
mLock . unlock ( ) ;
2010-05-14 03:26:45 -07:00
mAudioFlinger - > mLock . lock ( ) ;
audioConfigChanged_l ( configEvent - > mEvent , configEvent - > mParam ) ;
mAudioFlinger - > mLock . unlock ( ) ;
2009-07-17 12:17:14 -07:00
delete configEvent ;
mLock . lock ( ) ;
}
mLock . unlock ( ) ;
}
2009-11-07 00:01:32 -08:00
status_t AudioFlinger : : ThreadBase : : dumpBase ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
bool locked = tryLock ( mLock ) ;
if ( ! locked ) {
snprintf ( buffer , SIZE , " thread %p maybe dead locked \n " , this ) ;
write ( fd , buffer , strlen ( buffer ) ) ;
}
snprintf ( buffer , SIZE , " standby: %d \n " , mStandby ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Sample rate: %d \n " , mSampleRate ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Frame count: %d \n " , mFrameCount ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Channel Count: %d \n " , mChannelCount ) ;
result . append ( buffer ) ;
2011-05-24 15:53:33 -07:00
snprintf ( buffer , SIZE , " Channel Mask: 0x%08x \n " , mChannelMask ) ;
result . append ( buffer ) ;
2009-11-07 00:01:32 -08:00
snprintf ( buffer , SIZE , " Format: %d \n " , mFormat ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Frame size: %d \n " , mFrameSize ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " \n Pending setParameters commands: \n " ) ;
result . append ( buffer ) ;
result . append ( " Index Command " ) ;
for ( size_t i = 0 ; i < mNewParameters . size ( ) ; + + i ) {
snprintf ( buffer , SIZE , " \n %02d " , i ) ;
result . append ( buffer ) ;
result . append ( mNewParameters [ i ] ) ;
}
snprintf ( buffer , SIZE , " \n \n Pending config events: \n " ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Index event param \n " ) ;
result . append ( buffer ) ;
for ( size_t i = 0 ; i < mConfigEvents . size ( ) ; i + + ) {
snprintf ( buffer , SIZE , " %02d %02d %d \n " , i , mConfigEvents [ i ] - > mEvent , mConfigEvents [ i ] - > mParam ) ;
result . append ( buffer ) ;
}
result . append ( " \n " ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
if ( locked ) {
mLock . unlock ( ) ;
}
return NO_ERROR ;
}
2011-07-24 17:49:51 -07:00
status_t AudioFlinger : : ThreadBase : : dumpEffectChains ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
snprintf ( buffer , SIZE , " \n - %d Effect Chains: \n " , mEffectChains . size ( ) ) ;
write ( fd , buffer , strlen ( buffer ) ) ;
for ( size_t i = 0 ; i < mEffectChains . size ( ) ; + + i ) {
sp < EffectChain > chain = mEffectChains [ i ] ;
if ( chain ! = 0 ) {
chain - > dump ( fd , args ) ;
}
}
return NO_ERROR ;
}
2011-07-22 09:04:31 -07:00
void AudioFlinger : : ThreadBase : : acquireWakeLock ( )
{
Mutex : : Autolock _l ( mLock ) ;
acquireWakeLock_l ( ) ;
}
void AudioFlinger : : ThreadBase : : acquireWakeLock_l ( )
{
if ( mPowerManager = = 0 ) {
// use checkService() to avoid blocking if power service is not up yet
sp < IBinder > binder =
defaultServiceManager ( ) - > checkService ( String16 ( " power " ) ) ;
if ( binder = = 0 ) {
LOGW ( " Thread %s cannot connect to the power manager service " , mName ) ;
} else {
mPowerManager = interface_cast < IPowerManager > ( binder ) ;
binder - > linkToDeath ( mDeathRecipient ) ;
}
}
if ( mPowerManager ! = 0 ) {
sp < IBinder > binder = new BBinder ( ) ;
status_t status = mPowerManager - > acquireWakeLock ( POWERMANAGER_PARTIAL_WAKE_LOCK ,
binder ,
String16 ( mName ) ) ;
if ( status = = NO_ERROR ) {
mWakeLockToken = binder ;
}
LOGV ( " acquireWakeLock_l() %s status %d " , mName , status ) ;
}
}
void AudioFlinger : : ThreadBase : : releaseWakeLock ( )
{
Mutex : : Autolock _l ( mLock ) ;
2011-07-28 13:59:02 -07:00
releaseWakeLock_l ( ) ;
2011-07-22 09:04:31 -07:00
}
void AudioFlinger : : ThreadBase : : releaseWakeLock_l ( )
{
if ( mWakeLockToken ! = 0 ) {
LOGV ( " releaseWakeLock_l() %s " , mName ) ;
if ( mPowerManager ! = 0 ) {
mPowerManager - > releaseWakeLock ( mWakeLockToken , 0 ) ;
}
mWakeLockToken . clear ( ) ;
}
}
void AudioFlinger : : ThreadBase : : clearPowerManager ( )
{
Mutex : : Autolock _l ( mLock ) ;
releaseWakeLock_l ( ) ;
mPowerManager . clear ( ) ;
}
void AudioFlinger : : ThreadBase : : PMDeathRecipient : : binderDied ( const wp < IBinder > & who )
{
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
thread - > clearPowerManager ( ) ;
}
LOGW ( " power manager service died !!! " ) ;
}
2011-07-24 17:49:51 -07:00
2011-07-27 19:49:51 -07:00
void AudioFlinger : : ThreadBase : : setEffectSuspended (
const effect_uuid_t * type , bool suspend , int sessionId )
{
Mutex : : Autolock _l ( mLock ) ;
setEffectSuspended_l ( type , suspend , sessionId ) ;
}
void AudioFlinger : : ThreadBase : : setEffectSuspended_l (
const effect_uuid_t * type , bool suspend , int sessionId )
{
sp < EffectChain > chain ;
chain = getEffectChain_l ( sessionId ) ;
if ( chain ! = 0 ) {
if ( type ! = NULL ) {
chain - > setEffectSuspended_l ( type , suspend ) ;
} else {
chain - > setEffectSuspendedAll_l ( suspend ) ;
}
}
updateSuspendedSessions_l ( type , suspend , sessionId ) ;
}
void AudioFlinger : : ThreadBase : : checkSuspendOnAddEffectChain_l ( const sp < EffectChain > & chain )
{
int index = mSuspendedSessions . indexOfKey ( chain - > sessionId ( ) ) ;
if ( index < 0 ) {
return ;
}
KeyedVector < int , sp < SuspendedSessionDesc > > sessionEffects =
mSuspendedSessions . editValueAt ( index ) ;
for ( size_t i = 0 ; i < sessionEffects . size ( ) ; i + + ) {
sp < SuspendedSessionDesc > desc = sessionEffects . valueAt ( i ) ;
for ( int j = 0 ; j < desc - > mRefCount ; j + + ) {
if ( sessionEffects . keyAt ( i ) = = EffectChain : : kKeyForSuspendAll ) {
chain - > setEffectSuspendedAll_l ( true ) ;
} else {
LOGV ( " checkSuspendOnAddEffectChain_l() suspending effects %08x " ,
desc - > mType . timeLow ) ;
chain - > setEffectSuspended_l ( & desc - > mType , true ) ;
}
}
}
}
void AudioFlinger : : ThreadBase : : updateSuspendedSessions_l ( const effect_uuid_t * type ,
bool suspend ,
int sessionId )
{
int index = mSuspendedSessions . indexOfKey ( sessionId ) ;
KeyedVector < int , sp < SuspendedSessionDesc > > sessionEffects ;
if ( suspend ) {
if ( index > = 0 ) {
sessionEffects = mSuspendedSessions . editValueAt ( index ) ;
} else {
mSuspendedSessions . add ( sessionId , sessionEffects ) ;
}
} else {
if ( index < 0 ) {
return ;
}
sessionEffects = mSuspendedSessions . editValueAt ( index ) ;
}
int key = EffectChain : : kKeyForSuspendAll ;
if ( type ! = NULL ) {
key = type - > timeLow ;
}
index = sessionEffects . indexOfKey ( key ) ;
sp < SuspendedSessionDesc > desc ;
if ( suspend ) {
if ( index > = 0 ) {
desc = sessionEffects . valueAt ( index ) ;
} else {
desc = new SuspendedSessionDesc ( ) ;
if ( type ! = NULL ) {
memcpy ( & desc - > mType , type , sizeof ( effect_uuid_t ) ) ;
}
sessionEffects . add ( key , desc ) ;
LOGV ( " updateSuspendedSessions_l() suspend adding effect %08x " , key ) ;
}
desc - > mRefCount + + ;
} else {
if ( index < 0 ) {
return ;
}
desc = sessionEffects . valueAt ( index ) ;
if ( - - desc - > mRefCount = = 0 ) {
LOGV ( " updateSuspendedSessions_l() restore removing effect %08x " , key ) ;
sessionEffects . removeItemsAt ( index ) ;
if ( sessionEffects . isEmpty ( ) ) {
LOGV ( " updateSuspendedSessions_l() restore removing session %d " ,
sessionId ) ;
mSuspendedSessions . removeItem ( sessionId ) ;
}
}
}
if ( ! sessionEffects . isEmpty ( ) ) {
mSuspendedSessions . replaceValueFor ( sessionId , sessionEffects ) ;
}
}
void AudioFlinger : : ThreadBase : : checkSuspendOnEffectEnabled ( const sp < EffectModule > & effect ,
bool enabled ,
int sessionId )
{
Mutex : : Autolock _l ( mLock ) ;
2011-10-19 11:44:54 -07:00
checkSuspendOnEffectEnabled_l ( effect , enabled , sessionId ) ;
}
2011-07-27 19:49:51 -07:00
2011-10-19 11:44:54 -07:00
void AudioFlinger : : ThreadBase : : checkSuspendOnEffectEnabled_l ( const sp < EffectModule > & effect ,
bool enabled ,
int sessionId )
{
2011-08-10 10:37:50 -07:00
if ( mType ! = RECORD ) {
// suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on
// another session. This gives the priority to well behaved effect control panels
// and applications not using global effects.
if ( sessionId ! = AUDIO_SESSION_OUTPUT_MIX ) {
setEffectSuspended_l ( NULL , enabled , AUDIO_SESSION_OUTPUT_MIX ) ;
}
}
2011-07-27 19:49:51 -07:00
sp < EffectChain > chain = getEffectChain_l ( sessionId ) ;
if ( chain ! = 0 ) {
chain - > checkSuspendOnEffectEnabled ( effect , enabled ) ;
}
}
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2011-06-17 21:29:58 -07:00
AudioFlinger : : PlaybackThread : : PlaybackThread ( const sp < AudioFlinger > & audioFlinger ,
AudioStreamOut * output ,
int id ,
uint32_t device )
: ThreadBase ( audioFlinger , id , device ) ,
2009-08-06 08:49:39 -07:00
mMixBuffer ( 0 ) , mSuspended ( 0 ) , mBytesWritten ( 0 ) , mOutput ( output ) ,
2011-06-17 21:29:58 -07:00
mLastWriteTime ( 0 ) , mNumWrites ( 0 ) , mNumDelayedWrites ( 0 ) , mInWrite ( false )
2009-07-17 12:17:14 -07:00
{
2011-07-22 09:04:31 -07:00
snprintf ( mName , kNameLength , " AudioOut_%d " , id ) ;
2009-07-17 12:17:14 -07:00
readOutputParameters ( ) ;
mMasterVolume = mAudioFlinger - > masterVolume ( ) ;
mMasterMute = mAudioFlinger - > masterMute ( ) ;
2011-04-19 22:30:36 -07:00
for ( int stream = 0 ; stream < AUDIO_STREAM_CNT ; stream + + ) {
2009-07-17 12:17:14 -07:00
mStreamTypes [ stream ] . volume = mAudioFlinger - > streamVolumeInternal ( stream ) ;
mStreamTypes [ stream ] . mute = mAudioFlinger - > streamMute ( stream ) ;
2011-08-30 10:18:54 -07:00
mStreamTypes [ stream ] . valid = true ;
2009-07-17 12:17:14 -07:00
}
}
AudioFlinger : : PlaybackThread : : ~ PlaybackThread ( )
{
delete [ ] mMixBuffer ;
}
status_t AudioFlinger : : PlaybackThread : : dump ( int fd , const Vector < String16 > & args )
{
dumpInternals ( fd , args ) ;
dumpTracks ( fd , args ) ;
2010-06-01 23:49:17 -07:00
dumpEffectChains ( fd , args ) ;
2009-07-17 12:17:14 -07:00
return NO_ERROR ;
}
status_t AudioFlinger : : PlaybackThread : : dumpTracks ( int fd , const Vector < String16 > & args )
2009-03-03 19:31:44 -08:00
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
2009-07-17 12:17:14 -07:00
snprintf ( buffer , SIZE , " Output thread %p tracks \n " , this ) ;
2009-03-03 19:31:44 -08:00
result . append ( buffer ) ;
2011-05-24 15:53:33 -07:00
result . append ( " Name Clien Typ Fmt Chn mask Session Buf S M F SRate LeftV RighV Serv User Main buf Aux Buf \n " ) ;
2009-03-03 19:31:44 -08:00
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
2009-03-31 14:34:35 -07:00
sp < Track > track = mTracks [ i ] ;
if ( track ! = 0 ) {
track - > dump ( buffer , SIZE ) ;
result . append ( buffer ) ;
2009-03-03 19:31:44 -08:00
}
}
2009-07-17 12:17:14 -07:00
snprintf ( buffer , SIZE , " Output thread %p active tracks \n " , this ) ;
2009-03-03 19:31:44 -08:00
result . append ( buffer ) ;
2011-05-24 15:53:33 -07:00
result . append ( " Name Clien Typ Fmt Chn mask Session Buf S M F SRate LeftV RighV Serv User Main buf Aux Buf \n " ) ;
2009-03-03 19:31:44 -08:00
for ( size_t i = 0 ; i < mActiveTracks . size ( ) ; + + i ) {
2009-03-31 14:34:35 -07:00
wp < Track > wTrack = mActiveTracks [ i ] ;
2009-03-03 19:31:44 -08:00
if ( wTrack ! = 0 ) {
sp < Track > track = wTrack . promote ( ) ;
if ( track ! = 0 ) {
track - > dump ( buffer , SIZE ) ;
result . append ( buffer ) ;
}
}
}
write ( fd , result . string ( ) , result . size ( ) ) ;
return NO_ERROR ;
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : dumpInternals ( int fd , const Vector < String16 > & args )
2009-03-03 19:31:44 -08:00
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
2009-11-07 00:01:32 -08:00
snprintf ( buffer , SIZE , " \n Output thread %p internals \n " , this ) ;
2009-03-03 19:31:44 -08:00
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " last write occurred (msecs): %llu \n " , ns2ms ( systemTime ( ) - mLastWriteTime ) ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " total writes: %d \n " , mNumWrites ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " delayed writes: %d \n " , mNumDelayedWrites ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " blocked in write: %d \n " , mInWrite ) ;
result . append ( buffer ) ;
2009-12-18 05:47:48 -08:00
snprintf ( buffer , SIZE , " suspend count: %d \n " , mSuspended ) ;
result . append ( buffer ) ;
2010-06-01 23:49:17 -07:00
snprintf ( buffer , SIZE , " mix buffer : %p \n " , mMixBuffer ) ;
result . append ( buffer ) ;
2009-03-03 19:31:44 -08:00
write ( fd , result . string ( ) , result . size ( ) ) ;
2009-11-07 00:01:32 -08:00
dumpBase ( fd , args ) ;
2009-03-03 19:31:44 -08:00
return NO_ERROR ;
}
// Thread virtuals
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : readyToRun ( )
2009-03-03 19:31:44 -08:00
{
2011-08-07 16:32:26 -07:00
status_t status = initCheck ( ) ;
if ( status = = NO_ERROR ) {
LOGI ( " AudioFlinger's thread %p ready to run " , this ) ;
} else {
2009-03-03 19:31:44 -08:00
LOGE ( " No working audio driver found. " ) ;
}
2011-08-07 16:32:26 -07:00
return status ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : onFirstRef ( )
2009-03-03 19:31:44 -08:00
{
2011-07-22 09:04:31 -07:00
run ( mName , ANDROID_PRIORITY_URGENT_AUDIO ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
sp < AudioFlinger : : PlaybackThread : : Track > AudioFlinger : : PlaybackThread : : createTrack_l (
2009-03-03 19:31:44 -08:00
const sp < AudioFlinger : : Client > & client ,
int streamType ,
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2009-03-03 19:31:44 -08:00
int frameCount ,
const sp < IMemory > & sharedBuffer ,
2010-06-01 23:49:17 -07:00
int sessionId ,
2009-03-03 19:31:44 -08:00
status_t * status )
{
sp < Track > track ;
status_t lStatus ;
2009-07-17 12:17:14 -07:00
if ( mType = = DIRECT ) {
2011-05-24 15:53:33 -07:00
if ( ( format & AUDIO_FORMAT_MAIN_MASK ) = = AUDIO_FORMAT_PCM ) {
if ( sampleRate ! = mSampleRate | | format ! = mFormat | | channelMask ! = mChannelMask ) {
LOGE ( " createTrack_l() Bad parameter: sampleRate %d format %d, channelMask 0x%08x \" "
" for output %p with format %d " ,
sampleRate , format , channelMask , mOutput , mFormat ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
2009-07-17 12:17:14 -07:00
}
} else {
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
if ( sampleRate > mSampleRate * 2 ) {
LOGE ( " Sample rate out of range: %d mSampleRate %d " , sampleRate , mSampleRate ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
}
2009-03-03 19:31:44 -08:00
2011-06-17 21:29:58 -07:00
lStatus = initCheck ( ) ;
if ( lStatus ! = NO_ERROR ) {
2009-03-09 11:52:12 -07:00
LOGE ( " Audio driver not initialized. " ) ;
goto Exit ;
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
{ // scope for mLock
Mutex : : Autolock _l ( mLock ) ;
2010-07-13 04:45:46 -07:00
// all tracks in same audio session must share the same routing strategy otherwise
// conflicts will happen when tracks are moved from one output to another by audio policy
// manager
uint32_t strategy =
2011-04-19 22:30:36 -07:00
AudioSystem : : getStrategyForStream ( ( audio_stream_type_t ) streamType ) ;
2010-07-13 04:45:46 -07:00
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
sp < Track > t = mTracks [ i ] ;
if ( t ! = 0 ) {
if ( sessionId = = t - > sessionId ( ) & &
2011-04-19 22:30:36 -07:00
strategy ! = AudioSystem : : getStrategyForStream ( ( audio_stream_type_t ) t - > type ( ) ) ) {
2010-07-13 04:45:46 -07:00
lStatus = BAD_VALUE ;
goto Exit ;
}
}
}
2009-07-17 12:17:14 -07:00
track = new Track ( this , client , streamType , sampleRate , format ,
2011-05-24 15:53:33 -07:00
channelMask , frameCount , sharedBuffer , sessionId ) ;
2009-11-09 04:45:39 -08:00
if ( track - > getCblk ( ) = = NULL | | track - > name ( ) < 0 ) {
2009-07-17 12:17:14 -07:00
lStatus = NO_MEMORY ;
goto Exit ;
}
mTracks . add ( track ) ;
2010-06-01 23:49:17 -07:00
sp < EffectChain > chain = getEffectChain_l ( sessionId ) ;
if ( chain ! = 0 ) {
LOGV ( " createTrack_l() setting main buffer %p " , chain - > inBuffer ( ) ) ;
track - > setMainBuffer ( chain - > inBuffer ( ) ) ;
2011-04-19 22:30:36 -07:00
chain - > setStrategy ( AudioSystem : : getStrategyForStream ( ( audio_stream_type_t ) track - > type ( ) ) ) ;
2011-05-09 12:09:06 -07:00
chain - > incTrackCnt ( ) ;
2010-06-01 23:49:17 -07:00
}
2011-08-30 10:18:54 -07:00
// invalidate track immediately if the stream type was moved to another thread since
// createTrack() was called by the client process.
if ( ! mStreamTypes [ streamType ] . valid ) {
LOGW ( " createTrack_l() on thread %p: invalidating track on stream %d " ,
this , streamType ) ;
android_atomic_or ( CBLK_INVALID_ON , & track - > mCblk - > flags ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-03-09 11:52:12 -07:00
lStatus = NO_ERROR ;
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
Exit :
if ( status ) {
* status = lStatus ;
}
return track ;
}
uint32_t AudioFlinger : : PlaybackThread : : latency ( ) const
{
2011-08-07 16:32:26 -07:00
Mutex : : Autolock _l ( mLock ) ;
if ( initCheck ( ) = = NO_ERROR ) {
2011-04-18 16:57:27 -07:00
return mOutput - > stream - > get_latency ( mOutput - > stream ) ;
2011-08-07 16:32:26 -07:00
} else {
2009-07-17 12:17:14 -07:00
return 0 ;
}
}
status_t AudioFlinger : : PlaybackThread : : setMasterVolume ( float value )
{
mMasterVolume = value ;
return NO_ERROR ;
}
status_t AudioFlinger : : PlaybackThread : : setMasterMute ( bool muted )
{
mMasterMute = muted ;
return NO_ERROR ;
}
float AudioFlinger : : PlaybackThread : : masterVolume ( ) const
{
return mMasterVolume ;
}
bool AudioFlinger : : PlaybackThread : : masterMute ( ) const
{
return mMasterMute ;
}
status_t AudioFlinger : : PlaybackThread : : setStreamVolume ( int stream , float value )
{
mStreamTypes [ stream ] . volume = value ;
return NO_ERROR ;
}
status_t AudioFlinger : : PlaybackThread : : setStreamMute ( int stream , bool muted )
{
mStreamTypes [ stream ] . mute = muted ;
return NO_ERROR ;
}
float AudioFlinger : : PlaybackThread : : streamVolume ( int stream ) const
{
return mStreamTypes [ stream ] . volume ;
}
bool AudioFlinger : : PlaybackThread : : streamMute ( int stream ) const
{
return mStreamTypes [ stream ] . mute ;
}
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger : : PlaybackThread : : addTrack_l ( const sp < Track > & track )
{
status_t status = ALREADY_EXISTS ;
// set retry count for buffer fill
track - > mRetryCount = kMaxTrackStartupRetries ;
if ( mActiveTracks . indexOf ( track ) < 0 ) {
// the track is newly added, make sure it fills up all its
// buffers before playing. This is to ensure the client will
// effectively get the latency it requested.
track - > mFillingUpStatus = Track : : FS_FILLING ;
track - > mResetDone = false ;
mActiveTracks . add ( track ) ;
2010-06-01 23:49:17 -07:00
if ( track - > mainBuffer ( ) ! = mMixBuffer ) {
sp < EffectChain > chain = getEffectChain_l ( track - > sessionId ( ) ) ;
if ( chain ! = 0 ) {
LOGV ( " addTrack_l() starting track on chain %p for session %d " , chain . get ( ) , track - > sessionId ( ) ) ;
2011-05-09 12:09:06 -07:00
chain - > incActiveTrackCnt ( ) ;
2010-06-01 23:49:17 -07:00
}
}
2009-07-17 12:17:14 -07:00
status = NO_ERROR ;
}
LOGV ( " mWaitWorkCV.broadcast " ) ;
mWaitWorkCV . broadcast ( ) ;
return status ;
}
// destroyTrack_l() must be called with ThreadBase::mLock held
void AudioFlinger : : PlaybackThread : : destroyTrack_l ( const sp < Track > & track )
{
track - > mState = TrackBase : : TERMINATED ;
if ( mActiveTracks . indexOf ( track ) < 0 ) {
2011-05-09 12:09:06 -07:00
removeTrack_l ( track ) ;
}
}
void AudioFlinger : : PlaybackThread : : removeTrack_l ( const sp < Track > & track )
{
mTracks . remove ( track ) ;
deleteTrackName_l ( track - > name ( ) ) ;
sp < EffectChain > chain = getEffectChain_l ( track - > sessionId ( ) ) ;
if ( chain ! = 0 ) {
chain - > decTrackCnt ( ) ;
2009-07-17 12:17:14 -07:00
}
}
String8 AudioFlinger : : PlaybackThread : : getParameters ( const String8 & keys )
{
2011-08-07 16:32:26 -07:00
String8 out_s8 = String8 ( " " ) ;
2011-04-19 22:30:36 -07:00
char * s ;
2011-08-07 16:32:26 -07:00
Mutex : : Autolock _l ( mLock ) ;
if ( initCheck ( ) ! = NO_ERROR ) {
return out_s8 ;
}
2011-04-18 16:57:27 -07:00
s = mOutput - > stream - > common . get_parameters ( & mOutput - > stream - > common , keys . string ( ) ) ;
2011-04-19 22:30:36 -07:00
out_s8 = String8 ( s ) ;
free ( s ) ;
return out_s8 ;
2009-07-17 12:17:14 -07:00
}
2011-08-07 16:32:26 -07:00
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
2010-05-14 03:26:45 -07:00
void AudioFlinger : : PlaybackThread : : audioConfigChanged_l ( int event , int param ) {
2009-07-17 12:17:14 -07:00
AudioSystem : : OutputDescriptor desc ;
void * param2 = 0 ;
2010-05-14 03:26:45 -07:00
LOGV ( " PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d " , this , event , param ) ;
2009-07-17 12:17:14 -07:00
switch ( event ) {
case AudioSystem : : OUTPUT_OPENED :
case AudioSystem : : OUTPUT_CONFIG_CHANGED :
2011-05-24 15:53:33 -07:00
desc . channels = mChannelMask ;
2009-07-17 12:17:14 -07:00
desc . samplingRate = mSampleRate ;
desc . format = mFormat ;
desc . frameCount = mFrameCount ;
desc . latency = latency ( ) ;
param2 = & desc ;
break ;
case AudioSystem : : STREAM_CONFIG_CHANGED :
param2 = & param ;
case AudioSystem : : OUTPUT_CLOSED :
default :
break ;
}
2009-11-19 09:00:56 -08:00
mAudioFlinger - > audioConfigChanged_l ( event , mId , param2 ) ;
2009-07-17 12:17:14 -07:00
}
void AudioFlinger : : PlaybackThread : : readOutputParameters ( )
{
2011-04-18 16:57:27 -07:00
mSampleRate = mOutput - > stream - > common . get_sample_rate ( & mOutput - > stream - > common ) ;
2011-05-24 15:53:33 -07:00
mChannelMask = mOutput - > stream - > common . get_channels ( & mOutput - > stream - > common ) ;
mChannelCount = ( uint16_t ) popcount ( mChannelMask ) ;
2011-04-18 16:57:27 -07:00
mFormat = mOutput - > stream - > common . get_format ( & mOutput - > stream - > common ) ;
mFrameSize = ( uint16_t ) audio_stream_frame_size ( & mOutput - > stream - > common ) ;
mFrameCount = mOutput - > stream - > common . get_buffer_size ( & mOutput - > stream - > common ) / mFrameSize ;
2009-07-17 12:17:14 -07:00
// FIXME - Current mixer implementation only supports stereo output: Always
// Allocate a stereo buffer even if HW output is mono.
2010-06-01 23:49:17 -07:00
if ( mMixBuffer ! = NULL ) delete [ ] mMixBuffer ;
2009-07-17 12:17:14 -07:00
mMixBuffer = new int16_t [ mFrameCount * 2 ] ;
memset ( mMixBuffer , 0 , mFrameCount * 2 * sizeof ( int16_t ) ) ;
2010-06-01 23:49:17 -07:00
2010-07-13 04:45:46 -07:00
// force reconfiguration of effect chains and engines to take new buffer size and audio
// parameters into account
// Note that mLock is not held when readOutputParameters() is called from the constructor
// but in this case nothing is done below as no audio sessions have effect yet so it doesn't
// matter.
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
Vector < sp < EffectChain > > effectChains = mEffectChains ;
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
2010-07-28 01:32:47 -07:00
mAudioFlinger - > moveEffectChain_l ( effectChains [ i ] - > sessionId ( ) , this , this , false ) ;
2010-07-13 04:45:46 -07:00
}
2009-07-17 12:17:14 -07:00
}
2010-01-19 17:37:09 -08:00
status_t AudioFlinger : : PlaybackThread : : getRenderPosition ( uint32_t * halFrames , uint32_t * dspFrames )
{
if ( halFrames = = 0 | | dspFrames = = 0 ) {
return BAD_VALUE ;
}
2011-08-07 16:32:26 -07:00
Mutex : : Autolock _l ( mLock ) ;
2011-06-17 21:29:58 -07:00
if ( initCheck ( ) ! = NO_ERROR ) {
2010-01-19 17:37:09 -08:00
return INVALID_OPERATION ;
}
2011-04-18 16:57:27 -07:00
* halFrames = mBytesWritten / audio_stream_frame_size ( & mOutput - > stream - > common ) ;
2010-01-19 17:37:09 -08:00
2011-04-18 16:57:27 -07:00
return mOutput - > stream - > get_render_position ( mOutput - > stream , dspFrames ) ;
2010-01-19 17:37:09 -08:00
}
2010-07-28 01:32:47 -07:00
uint32_t AudioFlinger : : PlaybackThread : : hasAudioSession ( int sessionId )
2010-06-01 23:49:17 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
2010-07-28 01:32:47 -07:00
uint32_t result = 0 ;
2010-06-01 23:49:17 -07:00
if ( getEffectChain_l ( sessionId ) ! = 0 ) {
2010-07-28 01:32:47 -07:00
result = EFFECT_SESSION ;
2010-06-01 23:49:17 -07:00
}
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
sp < Track > track = mTracks [ i ] ;
2010-07-13 04:45:46 -07:00
if ( sessionId = = track - > sessionId ( ) & &
! ( track - > mCblk - > flags & CBLK_INVALID_MSK ) ) {
2010-07-28 01:32:47 -07:00
result | = TRACK_SESSION ;
break ;
2010-06-01 23:49:17 -07:00
}
}
2010-07-28 01:32:47 -07:00
return result ;
2010-06-01 23:49:17 -07:00
}
2010-07-13 04:45:46 -07:00
uint32_t AudioFlinger : : PlaybackThread : : getStrategyForSession_l ( int sessionId )
{
2011-04-19 22:30:36 -07:00
// session AUDIO_SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that
2010-07-13 04:45:46 -07:00
// it is moved to correct output by audio policy manager when A2DP is connected or disconnected
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_MIX ) {
return AudioSystem : : getStrategyForStream ( AUDIO_STREAM_MUSIC ) ;
2010-07-13 04:45:46 -07:00
}
for ( size_t i = 0 ; i < mTracks . size ( ) ; i + + ) {
sp < Track > track = mTracks [ i ] ;
if ( sessionId = = track - > sessionId ( ) & &
! ( track - > mCblk - > flags & CBLK_INVALID_MSK ) ) {
2011-04-19 22:30:36 -07:00
return AudioSystem : : getStrategyForStream ( ( audio_stream_type_t ) track - > type ( ) ) ;
2010-07-13 04:45:46 -07:00
}
}
2011-04-19 22:30:36 -07:00
return AudioSystem : : getStrategyForStream ( AUDIO_STREAM_MUSIC ) ;
2010-07-13 04:45:46 -07:00
}
2010-06-23 17:38:20 -07:00
2011-08-07 16:32:26 -07:00
AudioFlinger : : AudioStreamOut * AudioFlinger : : PlaybackThread : : getOutput ( )
{
Mutex : : Autolock _l ( mLock ) ;
return mOutput ;
}
AudioFlinger : : AudioStreamOut * AudioFlinger : : PlaybackThread : : clearOutput ( )
{
Mutex : : Autolock _l ( mLock ) ;
AudioStreamOut * output = mOutput ;
mOutput = NULL ;
return output ;
}
// this method must always be called either with ThreadBase mLock held or inside the thread loop
audio_stream_t * AudioFlinger : : PlaybackThread : : stream ( )
{
if ( mOutput = = NULL ) {
return NULL ;
}
return & mOutput - > stream - > common ;
}
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2011-04-18 16:57:27 -07:00
AudioFlinger : : MixerThread : : MixerThread ( const sp < AudioFlinger > & audioFlinger , AudioStreamOut * output , int id , uint32_t device )
2010-06-01 23:49:17 -07:00
: PlaybackThread ( audioFlinger , output , id , device ) ,
2009-07-17 12:17:14 -07:00
mAudioMixer ( 0 )
{
2011-06-17 21:29:58 -07:00
mType = ThreadBase : : MIXER ;
2009-07-17 12:17:14 -07:00
mAudioMixer = new AudioMixer ( mFrameCount , mSampleRate ) ;
// FIXME - Current mixer implementation only supports stereo output
if ( mChannelCount = = 1 ) {
LOGE ( " Invalid audio hardware channel count " ) ;
}
}
AudioFlinger : : MixerThread : : ~ MixerThread ( )
{
delete mAudioMixer ;
}
bool AudioFlinger : : MixerThread : : threadLoop ( )
{
Vector < sp < Track > > tracksToRemove ;
2009-11-09 23:32:22 -08:00
uint32_t mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
nsecs_t standbyTime = systemTime ( ) ;
size_t mixBufferSize = mFrameCount * mFrameSize ;
2009-09-30 03:09:03 -07:00
// FIXME: Relaxed timing because of a certain device that can't meet latency
// Should be reduced to 2x after the vendor fixes the driver issue
2011-10-18 15:42:27 -07:00
// increase threshold again due to low power audio mode. The way this warning threshold is
// calculated and its usefulness should be reconsidered anyway.
nsecs_t maxPeriod = seconds ( mFrameCount ) / mSampleRate * 15 ;
2009-09-30 03:09:03 -07:00
nsecs_t lastWarning = 0 ;
2009-11-09 23:32:22 -08:00
bool longStandbyExit = false ;
uint32_t activeSleepTime = activeSleepTimeUs ( ) ;
uint32_t idleSleepTime = idleSleepTimeUs ( ) ;
uint32_t sleepTime = idleSleepTime ;
2010-06-01 23:49:17 -07:00
Vector < sp < EffectChain > > effectChains ;
2011-07-08 15:26:12 -07:00
# ifdef DEBUG_CPU_USAGE
ThreadCpuUsage cpu ;
const CentralTendencyStatistics & stats = cpu . statistics ( ) ;
# endif
2009-07-17 12:17:14 -07:00
2011-07-22 09:04:31 -07:00
acquireWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
while ( ! exitPending ( ) )
{
2011-07-08 15:26:12 -07:00
# ifdef DEBUG_CPU_USAGE
cpu . sampleAndEnable ( ) ;
unsigned n = stats . n ( ) ;
// cpu.elapsed() is expensive, so don't call it every loop
if ( ( n & 127 ) = = 1 ) {
long long elapsed = cpu . elapsed ( ) ;
if ( elapsed > = DEBUG_CPU_USAGE * 1000000000LL ) {
double perLoop = elapsed / ( double ) n ;
double perLoop100 = perLoop * 0.01 ;
double mean = stats . mean ( ) ;
double stddev = stats . stddev ( ) ;
double minimum = stats . minimum ( ) ;
double maximum = stats . maximum ( ) ;
cpu . resetStatistics ( ) ;
LOGI ( " CPU usage over past %.1f secs (%u mixer loops at %.1f mean ms per loop): \n us per mix loop: mean=%.0f stddev=%.0f min=%.0f max=%.0f \n %% of wall: mean=%.1f stddev=%.1f min=%.1f max=%.1f " ,
elapsed * .000000001 , n , perLoop * .000001 ,
mean * .001 ,
stddev * .001 ,
minimum * .001 ,
maximum * .001 ,
mean / perLoop100 ,
stddev / perLoop100 ,
minimum / perLoop100 ,
maximum / perLoop100 ) ;
}
}
# endif
2009-07-17 12:17:14 -07:00
processConfigEvents ( ) ;
2009-11-09 23:32:22 -08:00
mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
{ // scope for mLock
Mutex : : Autolock _l ( mLock ) ;
if ( checkForNewParameters_l ( ) ) {
mixBufferSize = mFrameCount * mFrameSize ;
2009-09-30 03:09:03 -07:00
// FIXME: Relaxed timing because of a certain device that can't meet latency
// Should be reduced to 2x after the vendor fixes the driver issue
2011-10-18 15:42:27 -07:00
// increase threshold again due to low power audio mode. The way this warning
// threshold is calculated and its usefulness should be reconsidered anyway.
maxPeriod = seconds ( mFrameCount ) / mSampleRate * 15 ;
2009-11-09 23:32:22 -08:00
activeSleepTime = activeSleepTimeUs ( ) ;
idleSleepTime = idleSleepTimeUs ( ) ;
2009-07-17 12:17:14 -07:00
}
const SortedVector < wp < Track > > & activeTracks = mActiveTracks ;
// put audio hardware into standby after short delay
if UNLIKELY ( ( ! activeTracks . size ( ) & & systemTime ( ) > standbyTime ) | |
mSuspended ) {
if ( ! mStandby ) {
LOGV ( " Audio hardware entering standby, mixer %p, mSuspended %d \n " , this , mSuspended ) ;
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mStandby = true ;
mBytesWritten = 0 ;
}
if ( ! activeTracks . size ( ) & & mConfigEvents . isEmpty ( ) ) {
// we're about to wait, flush the binder command buffer
IPCThreadState : : self ( ) - > flushCommands ( ) ;
if ( exitPending ( ) ) break ;
2011-07-22 09:04:31 -07:00
releaseWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
// wait until we have something to do...
LOGV ( " MixerThread %p TID %d going to sleep \n " , this , gettid ( ) ) ;
mWaitWorkCV . wait ( mLock ) ;
LOGV ( " MixerThread %p TID %d waking up \n " , this , gettid ( ) ) ;
2011-07-22 09:04:31 -07:00
acquireWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
if ( mMasterMute = = false ) {
char value [ PROPERTY_VALUE_MAX ] ;
property_get ( " ro.audio.silent " , value , " 0 " ) ;
if ( atoi ( value ) ) {
LOGD ( " Silence is golden " ) ;
setMasterMute ( true ) ;
}
}
standbyTime = systemTime ( ) + kStandbyTimeInNsecs ;
2009-11-09 23:32:22 -08:00
sleepTime = idleSleepTime ;
2009-07-17 12:17:14 -07:00
continue ;
}
}
2009-11-09 23:32:22 -08:00
mixerStatus = prepareTracks_l ( activeTracks , & tracksToRemove ) ;
2010-06-01 23:49:17 -07:00
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
// or modified if an effect is created or deleted
2010-07-13 04:45:46 -07:00
lockEffectChains_l ( effectChains ) ;
2009-07-17 12:17:14 -07:00
}
2009-11-09 23:32:22 -08:00
if ( LIKELY ( mixerStatus = = MIXER_TRACKS_READY ) ) {
2009-09-22 00:35:48 -07:00
// mix buffers...
2010-06-01 23:49:17 -07:00
mAudioMixer - > process ( ) ;
2009-09-22 00:35:48 -07:00
sleepTime = 0 ;
standbyTime = systemTime ( ) + kStandbyTimeInNsecs ;
2010-06-01 23:49:17 -07:00
//TODO: delay standby when effects have a tail
2009-09-07 08:38:38 -07:00
} else {
2009-10-05 20:29:18 -07:00
// If no tracks are ready, sleep once for the duration of an output
// buffer size, then write 0s to the output
if ( sleepTime = = 0 ) {
2009-11-09 23:32:22 -08:00
if ( mixerStatus = = MIXER_TRACKS_ENABLED ) {
sleepTime = activeSleepTime ;
} else {
sleepTime = idleSleepTime ;
}
} else if ( mBytesWritten ! = 0 | |
( mixerStatus = = MIXER_TRACKS_ENABLED & & longStandbyExit ) ) {
2010-06-01 23:49:17 -07:00
memset ( mMixBuffer , 0 , mixBufferSize ) ;
2009-09-07 08:38:38 -07:00
sleepTime = 0 ;
2009-11-09 23:32:22 -08:00
LOGV_IF ( ( mBytesWritten = = 0 & & ( mixerStatus = = MIXER_TRACKS_ENABLED & & longStandbyExit ) ) , " anticipated start " ) ;
2009-09-07 08:38:38 -07:00
}
2010-06-01 23:49:17 -07:00
// TODO add standby time extension fct of effect tail
2009-09-22 00:35:48 -07:00
}
if ( mSuspended ) {
2010-08-18 18:13:17 -07:00
sleepTime = suspendSleepTimeUs ( ) ;
2009-09-22 00:35:48 -07:00
}
// sleepTime == 0 means we must write to audio hardware
if ( sleepTime = = 0 ) {
2010-06-01 23:49:17 -07:00
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
effectChains [ i ] - > process_l ( ) ;
}
// enable changes in effect chain
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2010-06-01 23:49:17 -07:00
mLastWriteTime = systemTime ( ) ;
mInWrite = true ;
mBytesWritten + = mixBufferSize ;
2011-04-18 16:57:27 -07:00
int bytesWritten = ( int ) mOutput - > stream - > write ( mOutput - > stream , mMixBuffer , mixBufferSize ) ;
2010-01-19 17:37:09 -08:00
if ( bytesWritten < 0 ) mBytesWritten - = mixBufferSize ;
2009-09-22 00:35:48 -07:00
mNumWrites + + ;
mInWrite = false ;
2009-09-30 03:09:03 -07:00
nsecs_t now = systemTime ( ) ;
nsecs_t delta = now - mLastWriteTime ;
2011-10-18 15:42:27 -07:00
if ( ! mStandby & & delta > maxPeriod ) {
2009-09-22 00:35:48 -07:00
mNumDelayedWrites + + ;
2009-09-30 03:09:03 -07:00
if ( ( now - lastWarning ) > kWarningThrottle ) {
LOGW ( " write blocked for %llu msecs, %d delayed writes, thread %p " ,
ns2ms ( delta ) , mNumDelayedWrites , this ) ;
lastWarning = now ;
}
2009-11-09 23:32:22 -08:00
if ( mStandby ) {
longStandbyExit = true ;
}
2009-07-17 12:17:14 -07:00
}
2009-11-09 23:32:22 -08:00
mStandby = false ;
2009-09-22 00:35:48 -07:00
} else {
2010-06-01 23:49:17 -07:00
// enable changes in effect chain
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2009-09-22 00:35:48 -07:00
usleep ( sleepTime ) ;
2009-07-17 12:17:14 -07:00
}
// finally let go of all our tracks, without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove . clear ( ) ;
2010-06-01 23:49:17 -07:00
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains . clear ( ) ;
2009-07-17 12:17:14 -07:00
}
if ( ! mStandby ) {
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
}
2011-07-22 09:04:31 -07:00
releaseWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " MixerThread %p exiting " , this ) ;
return false ;
}
// prepareTracks_l() must be called with ThreadBase::mLock held
2009-11-09 23:32:22 -08:00
uint32_t AudioFlinger : : MixerThread : : prepareTracks_l ( const SortedVector < wp < Track > > & activeTracks , Vector < sp < Track > > * tracksToRemove )
2009-07-17 12:17:14 -07:00
{
2009-11-09 23:32:22 -08:00
uint32_t mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
// find out which tracks need to be processed
size_t count = activeTracks . size ( ) ;
2010-06-01 23:49:17 -07:00
size_t mixedTracks = 0 ;
size_t tracksWithEffect = 0 ;
2010-03-05 12:18:01 -08:00
float masterVolume = mMasterVolume ;
bool masterMute = mMasterMute ;
2010-08-11 05:20:11 -07:00
if ( masterMute ) {
masterVolume = 0 ;
}
2010-06-01 23:49:17 -07:00
// Delegate master volume control to effect in output mix effect chain if needed
2011-04-19 22:30:36 -07:00
sp < EffectChain > chain = getEffectChain_l ( AUDIO_SESSION_OUTPUT_MIX ) ;
2010-06-01 23:49:17 -07:00
if ( chain ! = 0 ) {
2010-08-11 05:20:11 -07:00
uint32_t v = ( uint32_t ) ( masterVolume * ( 1 < < 24 ) ) ;
2010-07-15 12:50:15 -07:00
chain - > setVolume_l ( & v , & v ) ;
2010-06-01 23:49:17 -07:00
masterVolume = ( float ) ( ( v + ( 1 < < 23 ) ) > > 24 ) ;
chain . clear ( ) ;
}
2010-03-05 12:18:01 -08:00
2009-07-17 12:17:14 -07:00
for ( size_t i = 0 ; i < count ; i + + ) {
sp < Track > t = activeTracks [ i ] . promote ( ) ;
if ( t = = 0 ) continue ;
Track * const track = t . get ( ) ;
audio_track_cblk_t * cblk = track - > cblk ( ) ;
// The first time a track is added we wait
// for all its buffers to be filled before processing it
mAudioMixer - > setActiveTrack ( track - > name ( ) ) ;
2011-11-03 12:16:05 -07:00
// make sure that we have enough frames to mix one full buffer
uint32_t minFrames = 1 ;
if ( ! track - > isStopped ( ) & & ! track - > isPausing ( ) ) {
if ( t - > sampleRate ( ) = = ( int ) mSampleRate ) {
minFrames = mFrameCount ;
} else {
minFrames = ( mFrameCount * t - > sampleRate ( ) ) / mSampleRate + 1 ;
}
}
if ( ( cblk - > framesReady ( ) > = minFrames ) & & track - > isReady ( ) & &
2010-03-31 12:21:17 -07:00
! track - > isPaused ( ) & & ! track - > isTerminated ( ) )
2009-07-17 12:17:14 -07:00
{
2009-12-18 05:47:48 -08:00
//LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
2009-07-17 12:17:14 -07:00
2010-06-01 23:49:17 -07:00
mixedTracks + + ;
// track->mainBuffer() != mMixBuffer means there is an effect chain
// connected to the track
chain . clear ( ) ;
if ( track - > mainBuffer ( ) ! = mMixBuffer ) {
chain = getEffectChain_l ( track - > sessionId ( ) ) ;
// Delegate volume control to effect in track effect chain if needed
if ( chain ! = 0 ) {
tracksWithEffect + + ;
} else {
LOGW ( " prepareTracks_l(): track %08x attached to effect but no chain found on session %d " ,
track - > name ( ) , track - > sessionId ( ) ) ;
}
}
int param = AudioMixer : : VOLUME ;
if ( track - > mFillingUpStatus = = Track : : FS_FILLED ) {
// no ramp for the first volume setting
track - > mFillingUpStatus = Track : : FS_ACTIVE ;
if ( track - > mState = = TrackBase : : RESUMING ) {
track - > mState = TrackBase : : ACTIVE ;
param = AudioMixer : : RAMP_VOLUME ;
}
2011-02-28 16:52:51 -08:00
mAudioMixer - > setParameter ( AudioMixer : : RESAMPLE , AudioMixer : : RESET , NULL ) ;
2010-06-01 23:49:17 -07:00
} else if ( cblk - > server ! = 0 ) {
// If the track is stopped before the first frame was mixed,
// do not apply ramp
param = AudioMixer : : RAMP_VOLUME ;
}
2009-07-17 12:17:14 -07:00
// compute volume for this track
2010-09-10 17:44:44 -07:00
uint32_t vl , vr , va ;
2010-07-29 23:43:43 -07:00
if ( track - > isMuted ( ) | | track - > isPausing ( ) | |
2009-07-17 12:17:14 -07:00
mStreamTypes [ track - > type ( ) ] . mute ) {
2010-09-10 17:44:44 -07:00
vl = vr = va = 0 ;
2009-07-17 12:17:14 -07:00
if ( track - > isPausing ( ) ) {
track - > setPaused ( ) ;
}
} else {
2010-09-10 17:44:44 -07:00
2010-03-05 12:18:01 -08:00
// read original volumes with volume control
2009-07-17 12:17:14 -07:00
float typeVolume = mStreamTypes [ track - > type ( ) ] . volume ;
2010-03-05 12:18:01 -08:00
float v = masterVolume * typeVolume ;
2010-09-10 17:44:44 -07:00
vl = ( uint32_t ) ( v * cblk - > volume [ 0 ] ) < < 12 ;
vr = ( uint32_t ) ( v * cblk - > volume [ 1 ] ) < < 12 ;
2010-06-01 23:49:17 -07:00
2010-09-10 17:44:44 -07:00
va = ( uint32_t ) ( v * cblk - > sendLevel ) ;
}
// Delegate volume control to effect in track effect chain if needed
if ( chain ! = 0 & & chain - > setVolume_l ( & vl , & vr ) ) {
// Do not ramp volume if volume is controlled by effect
param = AudioMixer : : VOLUME ;
track - > mHasVolumeController = true ;
} else {
// force no volume ramp when volume controller was just disabled or removed
// from effect chain to avoid volume spike
if ( track - > mHasVolumeController ) {
2010-06-01 23:49:17 -07:00
param = AudioMixer : : VOLUME ;
}
2010-09-10 17:44:44 -07:00
track - > mHasVolumeController = false ;
2009-07-17 12:17:14 -07:00
}
2010-06-01 23:49:17 -07:00
2010-09-10 17:44:44 -07:00
// Convert volumes from 8.24 to 4.12 format
int16_t left , right , aux ;
uint32_t v_clamped = ( vl + ( 1 < < 11 ) ) > > 12 ;
if ( v_clamped > MAX_GAIN_INT ) v_clamped = MAX_GAIN_INT ;
left = int16_t ( v_clamped ) ;
v_clamped = ( vr + ( 1 < < 11 ) ) > > 12 ;
if ( v_clamped > MAX_GAIN_INT ) v_clamped = MAX_GAIN_INT ;
right = int16_t ( v_clamped ) ;
if ( va > MAX_GAIN_INT ) va = MAX_GAIN_INT ;
aux = int16_t ( va ) ;
2010-06-01 23:49:17 -07:00
// XXX: these things DON'T need to be done each time
mAudioMixer - > setBufferProvider ( track ) ;
mAudioMixer - > enable ( AudioMixer : : MIXING ) ;
mAudioMixer - > setParameter ( param , AudioMixer : : VOLUME0 , ( void * ) left ) ;
mAudioMixer - > setParameter ( param , AudioMixer : : VOLUME1 , ( void * ) right ) ;
mAudioMixer - > setParameter ( param , AudioMixer : : AUXLEVEL , ( void * ) aux ) ;
2009-07-17 12:17:14 -07:00
mAudioMixer - > setParameter (
AudioMixer : : TRACK ,
2010-06-01 23:49:17 -07:00
AudioMixer : : FORMAT , ( void * ) track - > format ( ) ) ;
2009-07-17 12:17:14 -07:00
mAudioMixer - > setParameter (
AudioMixer : : TRACK ,
2011-05-24 15:53:33 -07:00
AudioMixer : : CHANNEL_MASK , ( void * ) track - > channelMask ( ) ) ;
2009-07-17 12:17:14 -07:00
mAudioMixer - > setParameter (
AudioMixer : : RESAMPLE ,
AudioMixer : : SAMPLE_RATE ,
2010-06-01 23:49:17 -07:00
( void * ) ( cblk - > sampleRate ) ) ;
mAudioMixer - > setParameter (
AudioMixer : : TRACK ,
AudioMixer : : MAIN_BUFFER , ( void * ) track - > mainBuffer ( ) ) ;
mAudioMixer - > setParameter (
AudioMixer : : TRACK ,
AudioMixer : : AUX_BUFFER , ( void * ) track - > auxBuffer ( ) ) ;
2009-07-17 12:17:14 -07:00
// reset retry count
track - > mRetryCount = kMaxTrackRetries ;
2009-11-09 23:32:22 -08:00
mixerStatus = MIXER_TRACKS_READY ;
2009-07-17 12:17:14 -07:00
} else {
2009-12-18 05:47:48 -08:00
//LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this);
2009-07-17 12:17:14 -07:00
if ( track - > isStopped ( ) ) {
track - > reset ( ) ;
}
if ( track - > isTerminated ( ) | | track - > isStopped ( ) | | track - > isPaused ( ) ) {
// We have consumed all the buffers of this track.
// Remove it from the list of active tracks.
tracksToRemove - > add ( track ) ;
} else {
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if ( - - ( track - > mRetryCount ) < = 0 ) {
2009-10-05 20:29:18 -07:00
LOGV ( " BUFFER TIMEOUT: remove(%d) from active list on thread %p " , track - > name ( ) , this ) ;
2009-07-17 12:17:14 -07:00
tracksToRemove - > add ( track ) ;
2010-09-30 16:12:31 -07:00
// indicate to client process that the track was disabled because of underrun
2011-03-28 18:37:07 -07:00
android_atomic_or ( CBLK_DISABLED_ON , & cblk - > flags ) ;
2009-11-09 23:32:22 -08:00
} else if ( mixerStatus ! = MIXER_TRACKS_READY ) {
mixerStatus = MIXER_TRACKS_ENABLED ;
2009-07-17 12:17:14 -07:00
}
}
2010-06-01 23:49:17 -07:00
mAudioMixer - > disable ( AudioMixer : : MIXING ) ;
2009-07-17 12:17:14 -07:00
}
}
// remove all the tracks that need to be...
count = tracksToRemove - > size ( ) ;
if ( UNLIKELY ( count ) ) {
for ( size_t i = 0 ; i < count ; i + + ) {
const sp < Track > & track = tracksToRemove - > itemAt ( i ) ;
mActiveTracks . remove ( track ) ;
2010-06-01 23:49:17 -07:00
if ( track - > mainBuffer ( ) ! = mMixBuffer ) {
chain = getEffectChain_l ( track - > sessionId ( ) ) ;
if ( chain ! = 0 ) {
LOGV ( " stopping track on chain %p for session Id: %d " , chain . get ( ) , track - > sessionId ( ) ) ;
2011-05-09 12:09:06 -07:00
chain - > decActiveTrackCnt ( ) ;
2010-06-01 23:49:17 -07:00
}
}
2009-07-17 12:17:14 -07:00
if ( track - > isTerminated ( ) ) {
2011-05-09 12:09:06 -07:00
removeTrack_l ( track ) ;
2009-07-17 12:17:14 -07:00
}
}
}
2010-06-01 23:49:17 -07:00
// mix buffer must be cleared if all tracks are connected to an
// effect chain as in this case the mixer will not write to
// mix buffer and track effects will accumulate into it
if ( mixedTracks ! = 0 & & mixedTracks = = tracksWithEffect ) {
memset ( mMixBuffer , 0 , mFrameCount * mChannelCount * sizeof ( int16_t ) ) ;
}
2009-11-09 23:32:22 -08:00
return mixerStatus ;
2009-07-17 12:17:14 -07:00
}
2010-05-14 03:26:45 -07:00
void AudioFlinger : : MixerThread : : invalidateTracks ( int streamType )
2009-07-17 12:17:14 -07:00
{
2010-07-13 04:45:46 -07:00
LOGV ( " MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d " ,
this , streamType , mTracks . size ( ) ) ;
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-07-13 04:45:46 -07:00
2009-07-17 12:17:14 -07:00
size_t size = mTracks . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
sp < Track > t = mTracks [ i ] ;
if ( t - > type ( ) = = streamType ) {
2011-03-28 18:37:07 -07:00
android_atomic_or ( CBLK_INVALID_ON , & t - > mCblk - > flags ) ;
2010-05-14 03:26:45 -07:00
t - > mCblk - > cv . signal ( ) ;
2009-07-17 12:17:14 -07:00
}
2010-06-23 17:38:20 -07:00
}
}
2009-07-17 12:17:14 -07:00
2011-08-30 10:18:54 -07:00
void AudioFlinger : : PlaybackThread : : setStreamValid ( int streamType , bool valid )
{
LOGV ( " PlaybackThread::setStreamValid() thread %p, streamType %d, valid %d " ,
this , streamType , valid ) ;
Mutex : : Autolock _l ( mLock ) ;
mStreamTypes [ streamType ] . valid = valid ;
}
2009-07-17 12:17:14 -07:00
// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger : : MixerThread : : getTrackName_l ( )
{
return mAudioMixer - > getTrackName ( ) ;
}
// deleteTrackName_l() must be called with ThreadBase::mLock held
void AudioFlinger : : MixerThread : : deleteTrackName_l ( int name )
{
2009-12-07 10:53:10 -08:00
LOGV ( " remove track (%d) and delete from mixer " , name ) ;
2009-07-17 12:17:14 -07:00
mAudioMixer - > deleteTrackName ( name ) ;
}
// checkForNewParameters_l() must be called with ThreadBase::mLock held
bool AudioFlinger : : MixerThread : : checkForNewParameters_l ( )
{
bool reconfig = false ;
2009-08-04 09:45:33 -07:00
while ( ! mNewParameters . isEmpty ( ) ) {
2009-07-17 12:17:14 -07:00
status_t status = NO_ERROR ;
2009-08-04 09:45:33 -07:00
String8 keyValuePair = mNewParameters [ 0 ] ;
AudioParameter param = AudioParameter ( keyValuePair ) ;
2009-07-17 12:17:14 -07:00
int value ;
2009-08-04 09:45:33 -07:00
2009-07-17 12:17:14 -07:00
if ( param . getInt ( String8 ( AudioParameter : : keySamplingRate ) , value ) = = NO_ERROR ) {
reconfig = true ;
}
if ( param . getInt ( String8 ( AudioParameter : : keyFormat ) , value ) = = NO_ERROR ) {
2011-04-19 22:30:36 -07:00
if ( value ! = AUDIO_FORMAT_PCM_16_BIT ) {
2009-07-17 12:17:14 -07:00
status = BAD_VALUE ;
} else {
reconfig = true ;
}
}
if ( param . getInt ( String8 ( AudioParameter : : keyChannels ) , value ) = = NO_ERROR ) {
2011-04-19 22:30:36 -07:00
if ( value ! = AUDIO_CHANNEL_OUT_STEREO ) {
2009-07-17 12:17:14 -07:00
status = BAD_VALUE ;
} else {
reconfig = true ;
}
}
if ( param . getInt ( String8 ( AudioParameter : : keyFrameCount ) , value ) = = NO_ERROR ) {
// do not accept frame count changes if tracks are open as the track buffer
// size depends on frame count and correct behavior would not be garantied
// if frame count is changed after track creation
if ( ! mTracks . isEmpty ( ) ) {
status = INVALID_OPERATION ;
} else {
reconfig = true ;
}
}
2010-06-01 23:49:17 -07:00
if ( param . getInt ( String8 ( AudioParameter : : keyRouting ) , value ) = = NO_ERROR ) {
2011-02-24 14:51:45 -08:00
// when changing the audio output device, call addBatteryData to notify
// the change
2011-05-09 12:09:06 -07:00
if ( ( int ) mDevice ! = value ) {
2011-02-24 14:51:45 -08:00
uint32_t params = 0 ;
// check whether speaker is on
2011-04-19 22:30:36 -07:00
if ( value & AUDIO_DEVICE_OUT_SPEAKER ) {
2011-02-24 14:51:45 -08:00
params | = IMediaPlayerService : : kBatteryDataSpeakerOn ;
}
int deviceWithoutSpeaker
2011-04-19 22:30:36 -07:00
= AUDIO_DEVICE_OUT_ALL & ~ AUDIO_DEVICE_OUT_SPEAKER ;
2011-02-24 14:51:45 -08:00
// check if any other device (except speaker) is on
if ( value & deviceWithoutSpeaker ) {
params | = IMediaPlayerService : : kBatteryDataOtherAudioDeviceOn ;
}
if ( params ! = 0 ) {
addBatteryData ( params ) ;
}
}
2010-06-01 23:49:17 -07:00
// forward device change to effects that have requested to be
// aware of attached audio device.
mDevice = ( uint32_t ) value ;
for ( size_t i = 0 ; i < mEffectChains . size ( ) ; i + + ) {
2010-07-15 12:50:15 -07:00
mEffectChains [ i ] - > setDevice_l ( mDevice ) ;
2010-06-01 23:49:17 -07:00
}
}
2009-07-17 12:17:14 -07:00
if ( status = = NO_ERROR ) {
2011-04-18 16:57:27 -07:00
status = mOutput - > stream - > common . set_parameters ( & mOutput - > stream - > common ,
2011-04-19 22:30:36 -07:00
keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
if ( ! mStandby & & status = = INVALID_OPERATION ) {
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mStandby = true ;
mBytesWritten = 0 ;
2011-04-18 16:57:27 -07:00
status = mOutput - > stream - > common . set_parameters ( & mOutput - > stream - > common ,
2011-04-19 22:30:36 -07:00
keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
}
if ( status = = NO_ERROR & & reconfig ) {
delete mAudioMixer ;
readOutputParameters ( ) ;
mAudioMixer = new AudioMixer ( mFrameCount , mSampleRate ) ;
for ( size_t i = 0 ; i < mTracks . size ( ) ; i + + ) {
int name = getTrackName_l ( ) ;
if ( name < 0 ) break ;
mTracks [ i ] - > mName = name ;
2009-08-10 08:15:12 -07:00
// limit track sample rate to 2 x new output sample rate
if ( mTracks [ i ] - > mCblk - > sampleRate > 2 * sampleRate ( ) ) {
mTracks [ i ] - > mCblk - > sampleRate = 2 * sampleRate ( ) ;
}
2009-07-17 12:17:14 -07:00
}
2009-08-04 09:45:33 -07:00
sendConfigEvent_l ( AudioSystem : : OUTPUT_CONFIG_CHANGED ) ;
2009-07-17 12:17:14 -07:00
}
}
2009-11-07 00:01:32 -08:00
mNewParameters . removeAt ( 0 ) ;
2009-07-17 12:17:14 -07:00
mParamStatus = status ;
mParamCond . signal ( ) ;
2011-09-13 11:40:21 -07:00
// wait for condition with time out in case the thread calling ThreadBase::setParameters()
// already timed out waiting for the status and will never signal the condition.
mWaitWorkCV . waitRelative ( mLock , kSetParametersTimeout ) ;
2009-07-17 12:17:14 -07:00
}
return reconfig ;
}
status_t AudioFlinger : : MixerThread : : dumpInternals ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
PlaybackThread : : dumpInternals ( fd , args ) ;
snprintf ( buffer , SIZE , " AudioMixer tracks: %08x \n " , mAudioMixer - > trackNames ( ) ) ;
result . append ( buffer ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
return NO_ERROR ;
}
2009-11-09 23:32:22 -08:00
uint32_t AudioFlinger : : MixerThread : : activeSleepTimeUs ( )
2009-10-05 20:29:18 -07:00
{
2011-04-18 16:57:27 -07:00
return ( uint32_t ) ( mOutput - > stream - > get_latency ( mOutput - > stream ) * 1000 ) / 2 ;
2009-11-09 23:32:22 -08:00
}
uint32_t AudioFlinger : : MixerThread : : idleSleepTimeUs ( )
{
2010-07-29 06:50:24 -07:00
return ( uint32_t ) ( ( ( mFrameCount * 1000 ) / mSampleRate ) * 1000 ) / 2 ;
2009-10-05 20:29:18 -07:00
}
2010-08-18 18:13:17 -07:00
uint32_t AudioFlinger : : MixerThread : : suspendSleepTimeUs ( )
{
return ( uint32_t ) ( ( ( mFrameCount * 1000 ) / mSampleRate ) * 1000 ) ;
}
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2011-04-18 16:57:27 -07:00
AudioFlinger : : DirectOutputThread : : DirectOutputThread ( const sp < AudioFlinger > & audioFlinger , AudioStreamOut * output , int id , uint32_t device )
2010-06-01 23:49:17 -07:00
: PlaybackThread ( audioFlinger , output , id , device )
2009-07-17 12:17:14 -07:00
{
2011-06-17 21:29:58 -07:00
mType = ThreadBase : : DIRECT ;
2009-07-17 12:17:14 -07:00
}
AudioFlinger : : DirectOutputThread : : ~ DirectOutputThread ( )
{
}
2010-06-01 23:49:17 -07:00
static inline int16_t clamp16 ( int32_t sample )
{
if ( ( sample > > 15 ) ^ ( sample > > 31 ) )
sample = 0x7FFF ^ ( sample > > 31 ) ;
return sample ;
}
static inline
int32_t mul ( int16_t in , int16_t v )
{
# if defined(__arm__) && !defined(__thumb__)
int32_t out ;
asm ( " smulbb %[out], %[in], %[v] \n "
: [ out ] " =r " ( out )
: [ in ] " %r " ( in ) , [ v ] " r " ( v )
: ) ;
return out ;
# else
return in * int32_t ( v ) ;
# endif
}
void AudioFlinger : : DirectOutputThread : : applyVolume ( uint16_t leftVol , uint16_t rightVol , bool ramp )
{
// Do not apply volume on compressed audio
2011-04-19 22:30:36 -07:00
if ( ! audio_is_linear_pcm ( mFormat ) ) {
2010-06-01 23:49:17 -07:00
return ;
}
// convert to signed 16 bit before volume calculation
2011-04-19 22:30:36 -07:00
if ( mFormat = = AUDIO_FORMAT_PCM_8_BIT ) {
2010-06-01 23:49:17 -07:00
size_t count = mFrameCount * mChannelCount ;
uint8_t * src = ( uint8_t * ) mMixBuffer + count - 1 ;
int16_t * dst = mMixBuffer + count - 1 ;
while ( count - - ) {
* dst - - = ( int16_t ) ( * src - - ^ 0x80 ) < < 8 ;
}
}
size_t frameCount = mFrameCount ;
int16_t * out = mMixBuffer ;
if ( ramp ) {
if ( mChannelCount = = 1 ) {
int32_t d = ( ( int32_t ) leftVol - ( int32_t ) mLeftVolShort ) < < 16 ;
int32_t vlInc = d / ( int32_t ) frameCount ;
int32_t vl = ( ( int32_t ) mLeftVolShort < < 16 ) ;
do {
out [ 0 ] = clamp16 ( mul ( out [ 0 ] , vl > > 16 ) > > 12 ) ;
out + + ;
vl + = vlInc ;
} while ( - - frameCount ) ;
} else {
int32_t d = ( ( int32_t ) leftVol - ( int32_t ) mLeftVolShort ) < < 16 ;
int32_t vlInc = d / ( int32_t ) frameCount ;
d = ( ( int32_t ) rightVol - ( int32_t ) mRightVolShort ) < < 16 ;
int32_t vrInc = d / ( int32_t ) frameCount ;
int32_t vl = ( ( int32_t ) mLeftVolShort < < 16 ) ;
int32_t vr = ( ( int32_t ) mRightVolShort < < 16 ) ;
do {
out [ 0 ] = clamp16 ( mul ( out [ 0 ] , vl > > 16 ) > > 12 ) ;
out [ 1 ] = clamp16 ( mul ( out [ 1 ] , vr > > 16 ) > > 12 ) ;
out + = 2 ;
vl + = vlInc ;
vr + = vrInc ;
} while ( - - frameCount ) ;
}
} else {
if ( mChannelCount = = 1 ) {
do {
out [ 0 ] = clamp16 ( mul ( out [ 0 ] , leftVol ) > > 12 ) ;
out + + ;
} while ( - - frameCount ) ;
} else {
do {
out [ 0 ] = clamp16 ( mul ( out [ 0 ] , leftVol ) > > 12 ) ;
out [ 1 ] = clamp16 ( mul ( out [ 1 ] , rightVol ) > > 12 ) ;
out + = 2 ;
} while ( - - frameCount ) ;
}
}
// convert back to unsigned 8 bit after volume calculation
2011-04-19 22:30:36 -07:00
if ( mFormat = = AUDIO_FORMAT_PCM_8_BIT ) {
2010-06-01 23:49:17 -07:00
size_t count = mFrameCount * mChannelCount ;
int16_t * src = mMixBuffer ;
uint8_t * dst = ( uint8_t * ) mMixBuffer ;
while ( count - - ) {
* dst + + = ( uint8_t ) ( ( ( int32_t ) * src + + + ( 1 < < 7 ) ) > > 8 ) ^ 0x80 ;
}
}
mLeftVolShort = leftVol ;
mRightVolShort = rightVol ;
}
2009-07-17 12:17:14 -07:00
bool AudioFlinger : : DirectOutputThread : : threadLoop ( )
{
2009-11-09 23:32:22 -08:00
uint32_t mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
sp < Track > trackToRemove ;
sp < Track > activeTrack ;
nsecs_t standbyTime = systemTime ( ) ;
int8_t * curBuf ;
size_t mixBufferSize = mFrameCount * mFrameSize ;
2009-11-09 23:32:22 -08:00
uint32_t activeSleepTime = activeSleepTimeUs ( ) ;
uint32_t idleSleepTime = idleSleepTimeUs ( ) ;
uint32_t sleepTime = idleSleepTime ;
2010-03-11 14:47:00 -08:00
// use shorter standby delay as on normal output to release
// hardware resources as soon as possible
nsecs_t standbyDelay = microseconds ( activeSleepTime * 2 ) ;
2009-11-09 23:32:22 -08:00
2011-07-22 09:04:31 -07:00
acquireWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
while ( ! exitPending ( ) )
{
2010-06-01 23:49:17 -07:00
bool rampVolume ;
uint16_t leftVol ;
uint16_t rightVol ;
Vector < sp < EffectChain > > effectChains ;
2009-07-17 12:17:14 -07:00
processConfigEvents ( ) ;
2009-11-09 23:32:22 -08:00
mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
{ // scope for the mLock
Mutex : : Autolock _l ( mLock ) ;
if ( checkForNewParameters_l ( ) ) {
mixBufferSize = mFrameCount * mFrameSize ;
2009-11-09 23:32:22 -08:00
activeSleepTime = activeSleepTimeUs ( ) ;
idleSleepTime = idleSleepTimeUs ( ) ;
2010-03-11 14:47:00 -08:00
standbyDelay = microseconds ( activeSleepTime * 2 ) ;
2009-07-17 12:17:14 -07:00
}
// put audio hardware into standby after short delay
if UNLIKELY ( ( ! mActiveTracks . size ( ) & & systemTime ( ) > standbyTime ) | |
mSuspended ) {
// wait until we have something to do...
if ( ! mStandby ) {
LOGV ( " Audio hardware entering standby, mixer %p \n " , this ) ;
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mStandby = true ;
mBytesWritten = 0 ;
}
if ( ! mActiveTracks . size ( ) & & mConfigEvents . isEmpty ( ) ) {
// we're about to wait, flush the binder command buffer
IPCThreadState : : self ( ) - > flushCommands ( ) ;
if ( exitPending ( ) ) break ;
2011-07-22 09:04:31 -07:00
releaseWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " DirectOutputThread %p TID %d going to sleep \n " , this , gettid ( ) ) ;
mWaitWorkCV . wait ( mLock ) ;
LOGV ( " DirectOutputThread %p TID %d waking up in active mode \n " , this , gettid ( ) ) ;
2011-07-22 09:04:31 -07:00
acquireWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
if ( mMasterMute = = false ) {
char value [ PROPERTY_VALUE_MAX ] ;
property_get ( " ro.audio.silent " , value , " 0 " ) ;
if ( atoi ( value ) ) {
LOGD ( " Silence is golden " ) ;
setMasterMute ( true ) ;
}
}
2010-03-11 14:47:00 -08:00
standbyTime = systemTime ( ) + standbyDelay ;
2009-11-09 23:32:22 -08:00
sleepTime = idleSleepTime ;
2009-07-17 12:17:14 -07:00
continue ;
}
}
2010-06-01 23:49:17 -07:00
effectChains = mEffectChains ;
2009-07-17 12:17:14 -07:00
// find out which tracks need to be processed
if ( mActiveTracks . size ( ) ! = 0 ) {
sp < Track > t = mActiveTracks [ 0 ] . promote ( ) ;
if ( t = = 0 ) continue ;
Track * const track = t . get ( ) ;
audio_track_cblk_t * cblk = track - > cblk ( ) ;
// The first time a track is added we wait
// for all its buffers to be filled before processing it
2010-10-05 14:41:42 -07:00
if ( cblk - > framesReady ( ) & & track - > isReady ( ) & &
2010-04-09 06:11:48 -07:00
! track - > isPaused ( ) & & ! track - > isTerminated ( ) )
2009-07-17 12:17:14 -07:00
{
//LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
2010-06-01 23:49:17 -07:00
if ( track - > mFillingUpStatus = = Track : : FS_FILLED ) {
track - > mFillingUpStatus = Track : : FS_ACTIVE ;
mLeftVolFloat = mRightVolFloat = 0 ;
mLeftVolShort = mRightVolShort = 0 ;
if ( track - > mState = = TrackBase : : RESUMING ) {
track - > mState = TrackBase : : ACTIVE ;
rampVolume = true ;
}
} else if ( cblk - > server ! = 0 ) {
// If the track is stopped before the first frame was mixed,
// do not apply ramp
rampVolume = true ;
}
2009-07-17 12:17:14 -07:00
// compute volume for this track
float left , right ;
if ( track - > isMuted ( ) | | mMasterMute | | track - > isPausing ( ) | |
mStreamTypes [ track - > type ( ) ] . mute ) {
left = right = 0 ;
if ( track - > isPausing ( ) ) {
track - > setPaused ( ) ;
}
} else {
float typeVolume = mStreamTypes [ track - > type ( ) ] . volume ;
float v = mMasterVolume * typeVolume ;
float v_clamped = v * cblk - > volume [ 0 ] ;
if ( v_clamped > MAX_GAIN ) v_clamped = MAX_GAIN ;
left = v_clamped / MAX_GAIN ;
v_clamped = v * cblk - > volume [ 1 ] ;
if ( v_clamped > MAX_GAIN ) v_clamped = MAX_GAIN ;
right = v_clamped / MAX_GAIN ;
}
2010-06-01 23:49:17 -07:00
if ( left ! = mLeftVolFloat | | right ! = mRightVolFloat ) {
mLeftVolFloat = left ;
mRightVolFloat = right ;
2009-07-17 12:17:14 -07:00
2010-06-01 23:49:17 -07:00
// If audio HAL implements volume control,
// force software volume to nominal value
2011-04-18 16:57:27 -07:00
if ( mOutput - > stream - > set_volume ( mOutput - > stream , left , right ) = = NO_ERROR ) {
2010-06-01 23:49:17 -07:00
left = 1.0f ;
right = 1.0f ;
2009-07-17 12:17:14 -07:00
}
2010-06-01 23:49:17 -07:00
// Convert volumes from float to 8.24
uint32_t vl = ( uint32_t ) ( left * ( 1 < < 24 ) ) ;
uint32_t vr = ( uint32_t ) ( right * ( 1 < < 24 ) ) ;
// Delegate volume control to effect in track effect chain if needed
// only one effect chain can be present on DirectOutputThread, so if
// there is one, the track is connected to it
if ( ! effectChains . isEmpty ( ) ) {
2010-09-10 17:44:44 -07:00
// Do not ramp volume if volume is controlled by effect
2010-07-15 12:50:15 -07:00
if ( effectChains [ 0 ] - > setVolume_l ( & vl , & vr ) ) {
2010-06-01 23:49:17 -07:00
rampVolume = false ;
}
}
// Convert volumes from 8.24 to 4.12 format
uint32_t v_clamped = ( vl + ( 1 < < 11 ) ) > > 12 ;
if ( v_clamped > MAX_GAIN_INT ) v_clamped = MAX_GAIN_INT ;
leftVol = ( uint16_t ) v_clamped ;
v_clamped = ( vr + ( 1 < < 11 ) ) > > 12 ;
if ( v_clamped > MAX_GAIN_INT ) v_clamped = MAX_GAIN_INT ;
rightVol = ( uint16_t ) v_clamped ;
} else {
leftVol = mLeftVolShort ;
rightVol = mRightVolShort ;
rampVolume = false ;
2009-07-17 12:17:14 -07:00
}
// reset retry count
2010-03-11 14:47:00 -08:00
track - > mRetryCount = kMaxTrackRetriesDirect ;
2009-07-17 12:17:14 -07:00
activeTrack = t ;
2009-11-09 23:32:22 -08:00
mixerStatus = MIXER_TRACKS_READY ;
2009-07-17 12:17:14 -07:00
} else {
//LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
if ( track - > isStopped ( ) ) {
track - > reset ( ) ;
}
if ( track - > isTerminated ( ) | | track - > isStopped ( ) | | track - > isPaused ( ) ) {
// We have consumed all the buffers of this track.
// Remove it from the list of active tracks.
trackToRemove = track ;
} else {
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if ( - - ( track - > mRetryCount ) < = 0 ) {
LOGV ( " BUFFER TIMEOUT: remove(%d) from active list " , track - > name ( ) ) ;
trackToRemove = track ;
2009-11-09 23:32:22 -08:00
} else {
mixerStatus = MIXER_TRACKS_ENABLED ;
2009-07-17 12:17:14 -07:00
}
2009-11-09 23:32:22 -08:00
}
2009-07-17 12:17:14 -07:00
}
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
// remove all the tracks that need to be...
if ( UNLIKELY ( trackToRemove ! = 0 ) ) {
mActiveTracks . remove ( trackToRemove ) ;
2010-06-01 23:49:17 -07:00
if ( ! effectChains . isEmpty ( ) ) {
2010-07-13 04:45:46 -07:00
LOGV ( " stopping track on chain %p for session Id: %d " , effectChains [ 0 ] . get ( ) ,
trackToRemove - > sessionId ( ) ) ;
2011-05-09 12:09:06 -07:00
effectChains [ 0 ] - > decActiveTrackCnt ( ) ;
2010-06-01 23:49:17 -07:00
}
2009-07-17 12:17:14 -07:00
if ( trackToRemove - > isTerminated ( ) ) {
2011-05-09 12:09:06 -07:00
removeTrack_l ( trackToRemove ) ;
2009-07-17 12:17:14 -07:00
}
}
2010-06-01 23:49:17 -07:00
2010-07-13 04:45:46 -07:00
lockEffectChains_l ( effectChains ) ;
2009-07-17 12:17:14 -07:00
}
2009-11-09 23:32:22 -08:00
if ( LIKELY ( mixerStatus = = MIXER_TRACKS_READY ) ) {
2009-09-22 00:35:48 -07:00
AudioBufferProvider : : Buffer buffer ;
size_t frameCount = mFrameCount ;
curBuf = ( int8_t * ) mMixBuffer ;
// output audio to hardware
2010-06-01 23:49:17 -07:00
while ( frameCount ) {
2009-09-22 00:35:48 -07:00
buffer . frameCount = frameCount ;
activeTrack - > getNextBuffer ( & buffer ) ;
if ( UNLIKELY ( buffer . raw = = 0 ) ) {
memset ( curBuf , 0 , frameCount * mFrameSize ) ;
break ;
2009-07-17 12:17:14 -07:00
}
2009-09-22 00:35:48 -07:00
memcpy ( curBuf , buffer . raw , buffer . frameCount * mFrameSize ) ;
frameCount - = buffer . frameCount ;
curBuf + = buffer . frameCount * mFrameSize ;
activeTrack - > releaseBuffer ( & buffer ) ;
}
sleepTime = 0 ;
2010-03-11 14:47:00 -08:00
standbyTime = systemTime ( ) + standbyDelay ;
2009-09-22 00:35:48 -07:00
} else {
2009-10-05 20:29:18 -07:00
if ( sleepTime = = 0 ) {
2009-11-09 23:32:22 -08:00
if ( mixerStatus = = MIXER_TRACKS_ENABLED ) {
sleepTime = activeSleepTime ;
} else {
sleepTime = idleSleepTime ;
}
2011-04-19 22:30:36 -07:00
} else if ( mBytesWritten ! = 0 & & audio_is_linear_pcm ( mFormat ) ) {
2009-09-22 00:35:48 -07:00
memset ( mMixBuffer , 0 , mFrameCount * mFrameSize ) ;
2009-09-07 08:38:38 -07:00
sleepTime = 0 ;
}
2009-09-22 00:35:48 -07:00
}
2009-09-07 08:38:38 -07:00
2009-09-22 00:35:48 -07:00
if ( mSuspended ) {
2010-08-18 18:13:17 -07:00
sleepTime = suspendSleepTimeUs ( ) ;
2009-09-22 00:35:48 -07:00
}
// sleepTime == 0 means we must write to audio hardware
if ( sleepTime = = 0 ) {
2010-06-01 23:49:17 -07:00
if ( mixerStatus = = MIXER_TRACKS_READY ) {
applyVolume ( leftVol , rightVol , rampVolume ) ;
}
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
effectChains [ i ] - > process_l ( ) ;
}
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2010-06-01 23:49:17 -07:00
2009-09-22 00:35:48 -07:00
mLastWriteTime = systemTime ( ) ;
mInWrite = true ;
2010-01-19 17:37:09 -08:00
mBytesWritten + = mixBufferSize ;
2011-04-18 16:57:27 -07:00
int bytesWritten = ( int ) mOutput - > stream - > write ( mOutput - > stream , mMixBuffer , mixBufferSize ) ;
2010-01-19 17:37:09 -08:00
if ( bytesWritten < 0 ) mBytesWritten - = mixBufferSize ;
2009-09-22 00:35:48 -07:00
mNumWrites + + ;
mInWrite = false ;
mStandby = false ;
} else {
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2009-09-22 00:35:48 -07:00
usleep ( sleepTime ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
// finally let go of removed track, without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
trackToRemove . clear ( ) ;
activeTrack . clear ( ) ;
2010-06-01 23:49:17 -07:00
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains . clear ( ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
if ( ! mStandby ) {
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-03-03 19:31:44 -08:00
}
2011-07-22 09:04:31 -07:00
releaseWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " DirectOutputThread %p exiting " , this ) ;
return false ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger : : DirectOutputThread : : getTrackName_l ( )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
return 0 ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
// deleteTrackName_l() must be called with ThreadBase::mLock held
void AudioFlinger : : DirectOutputThread : : deleteTrackName_l ( int name )
2009-03-03 19:31:44 -08:00
{
}
2009-07-17 12:17:14 -07:00
// checkForNewParameters_l() must be called with ThreadBase::mLock held
bool AudioFlinger : : DirectOutputThread : : checkForNewParameters_l ( )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
bool reconfig = false ;
2009-03-03 19:31:44 -08:00
2009-08-04 09:45:33 -07:00
while ( ! mNewParameters . isEmpty ( ) ) {
2009-07-17 12:17:14 -07:00
status_t status = NO_ERROR ;
2009-08-04 09:45:33 -07:00
String8 keyValuePair = mNewParameters [ 0 ] ;
AudioParameter param = AudioParameter ( keyValuePair ) ;
2009-07-17 12:17:14 -07:00
int value ;
2009-08-04 09:45:33 -07:00
2009-07-17 12:17:14 -07:00
if ( param . getInt ( String8 ( AudioParameter : : keyFrameCount ) , value ) = = NO_ERROR ) {
// do not accept frame count changes if tracks are open as the track buffer
// size depends on frame count and correct behavior would not be garantied
// if frame count is changed after track creation
if ( ! mTracks . isEmpty ( ) ) {
status = INVALID_OPERATION ;
} else {
reconfig = true ;
}
}
if ( status = = NO_ERROR ) {
2011-04-18 16:57:27 -07:00
status = mOutput - > stream - > common . set_parameters ( & mOutput - > stream - > common ,
2011-04-19 22:30:36 -07:00
keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
if ( ! mStandby & & status = = INVALID_OPERATION ) {
2011-04-18 16:57:27 -07:00
mOutput - > stream - > common . standby ( & mOutput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mStandby = true ;
mBytesWritten = 0 ;
2011-04-18 16:57:27 -07:00
status = mOutput - > stream - > common . set_parameters ( & mOutput - > stream - > common ,
2011-04-19 22:30:36 -07:00
keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
}
if ( status = = NO_ERROR & & reconfig ) {
readOutputParameters ( ) ;
2009-08-04 09:45:33 -07:00
sendConfigEvent_l ( AudioSystem : : OUTPUT_CONFIG_CHANGED ) ;
2009-07-17 12:17:14 -07:00
}
}
2009-11-07 00:01:32 -08:00
mNewParameters . removeAt ( 0 ) ;
2009-07-17 12:17:14 -07:00
mParamStatus = status ;
mParamCond . signal ( ) ;
2011-09-13 11:40:21 -07:00
// wait for condition with time out in case the thread calling ThreadBase::setParameters()
// already timed out waiting for the status and will never signal the condition.
mWaitWorkCV . waitRelative ( mLock , kSetParametersTimeout ) ;
2009-01-22 00:13:42 -08:00
}
2009-07-17 12:17:14 -07:00
return reconfig ;
2009-03-03 19:31:44 -08:00
}
2009-11-09 23:32:22 -08:00
uint32_t AudioFlinger : : DirectOutputThread : : activeSleepTimeUs ( )
2009-10-05 20:29:18 -07:00
{
uint32_t time ;
2011-04-19 22:30:36 -07:00
if ( audio_is_linear_pcm ( mFormat ) ) {
2011-04-18 16:57:27 -07:00
time = ( uint32_t ) ( mOutput - > stream - > get_latency ( mOutput - > stream ) * 1000 ) / 2 ;
2009-11-09 23:32:22 -08:00
} else {
time = 10000 ;
}
return time ;
}
uint32_t AudioFlinger : : DirectOutputThread : : idleSleepTimeUs ( )
{
uint32_t time ;
2011-04-19 22:30:36 -07:00
if ( audio_is_linear_pcm ( mFormat ) ) {
2010-07-29 06:50:24 -07:00
time = ( uint32_t ) ( ( ( mFrameCount * 1000 ) / mSampleRate ) * 1000 ) / 2 ;
2009-10-05 20:29:18 -07:00
} else {
time = 10000 ;
}
return time ;
}
2010-08-18 18:13:17 -07:00
uint32_t AudioFlinger : : DirectOutputThread : : suspendSleepTimeUs ( )
{
uint32_t time ;
2011-04-19 22:30:36 -07:00
if ( audio_is_linear_pcm ( mFormat ) ) {
2010-08-18 18:13:17 -07:00
time = ( uint32_t ) ( ( ( mFrameCount * 1000 ) / mSampleRate ) * 1000 ) ;
} else {
time = 10000 ;
}
return time ;
}
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2009-03-03 19:31:44 -08:00
2009-11-19 09:00:56 -08:00
AudioFlinger : : DuplicatingThread : : DuplicatingThread ( const sp < AudioFlinger > & audioFlinger , AudioFlinger : : MixerThread * mainThread , int id )
2010-06-01 23:49:17 -07:00
: MixerThread ( audioFlinger , mainThread - > getOutput ( ) , id , mainThread - > device ( ) ) , mWaitTimeMs ( UINT_MAX )
2009-03-03 19:31:44 -08:00
{
2011-06-17 21:29:58 -07:00
mType = ThreadBase : : DUPLICATING ;
2009-07-17 12:17:14 -07:00
addOutputTrack ( mainThread ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
AudioFlinger : : DuplicatingThread : : ~ DuplicatingThread ( )
2009-03-03 19:31:44 -08:00
{
2009-12-07 10:53:10 -08:00
for ( size_t i = 0 ; i < mOutputTracks . size ( ) ; i + + ) {
mOutputTracks [ i ] - > destroy ( ) ;
}
2009-07-17 12:17:14 -07:00
mOutputTracks . clear ( ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
bool AudioFlinger : : DuplicatingThread : : threadLoop ( )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
Vector < sp < Track > > tracksToRemove ;
2009-11-09 23:32:22 -08:00
uint32_t mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
nsecs_t standbyTime = systemTime ( ) ;
size_t mixBufferSize = mFrameCount * mFrameSize ;
SortedVector < sp < OutputTrack > > outputTracks ;
2009-10-05 20:29:18 -07:00
uint32_t writeFrames = 0 ;
2009-11-09 23:32:22 -08:00
uint32_t activeSleepTime = activeSleepTimeUs ( ) ;
uint32_t idleSleepTime = idleSleepTimeUs ( ) ;
uint32_t sleepTime = idleSleepTime ;
2010-06-01 23:49:17 -07:00
Vector < sp < EffectChain > > effectChains ;
2009-03-03 19:31:44 -08:00
2011-07-22 09:04:31 -07:00
acquireWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
while ( ! exitPending ( ) )
{
processConfigEvents ( ) ;
2009-03-03 19:31:44 -08:00
2009-11-09 23:32:22 -08:00
mixerStatus = MIXER_IDLE ;
2009-07-17 12:17:14 -07:00
{ // scope for the mLock
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
if ( checkForNewParameters_l ( ) ) {
mixBufferSize = mFrameCount * mFrameSize ;
2009-12-18 05:47:48 -08:00
updateWaitTime ( ) ;
2009-11-09 23:32:22 -08:00
activeSleepTime = activeSleepTimeUs ( ) ;
idleSleepTime = idleSleepTimeUs ( ) ;
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
const SortedVector < wp < Track > > & activeTracks = mActiveTracks ;
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
for ( size_t i = 0 ; i < mOutputTracks . size ( ) ; i + + ) {
outputTracks . add ( mOutputTracks [ i ] ) ;
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
// put audio hardware into standby after short delay
if UNLIKELY ( ( ! activeTracks . size ( ) & & systemTime ( ) > standbyTime ) | |
mSuspended ) {
if ( ! mStandby ) {
for ( size_t i = 0 ; i < outputTracks . size ( ) ; i + + ) {
outputTracks [ i ] - > stop ( ) ;
}
mStandby = true ;
mBytesWritten = 0 ;
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
if ( ! activeTracks . size ( ) & & mConfigEvents . isEmpty ( ) ) {
// we're about to wait, flush the binder command buffer
IPCThreadState : : self ( ) - > flushCommands ( ) ;
outputTracks . clear ( ) ;
if ( exitPending ( ) ) break ;
2011-07-22 09:04:31 -07:00
releaseWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " DuplicatingThread %p TID %d going to sleep \n " , this , gettid ( ) ) ;
mWaitWorkCV . wait ( mLock ) ;
LOGV ( " DuplicatingThread %p TID %d waking up \n " , this , gettid ( ) ) ;
2011-07-22 09:04:31 -07:00
acquireWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
if ( mMasterMute = = false ) {
char value [ PROPERTY_VALUE_MAX ] ;
property_get ( " ro.audio.silent " , value , " 0 " ) ;
if ( atoi ( value ) ) {
LOGD ( " Silence is golden " ) ;
setMasterMute ( true ) ;
}
}
2009-03-03 19:31:44 -08:00
2009-07-17 12:17:14 -07:00
standbyTime = systemTime ( ) + kStandbyTimeInNsecs ;
2009-11-09 23:32:22 -08:00
sleepTime = idleSleepTime ;
2009-07-17 12:17:14 -07:00
continue ;
}
}
2009-03-03 19:31:44 -08:00
2009-11-09 23:32:22 -08:00
mixerStatus = prepareTracks_l ( activeTracks , & tracksToRemove ) ;
2010-06-01 23:49:17 -07:00
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
// or modified if an effect is created or deleted
2010-07-13 04:45:46 -07:00
lockEffectChains_l ( effectChains ) ;
2009-09-22 00:35:48 -07:00
}
2009-01-22 00:13:42 -08:00
2009-11-09 23:32:22 -08:00
if ( LIKELY ( mixerStatus = = MIXER_TRACKS_READY ) ) {
2009-07-17 12:17:14 -07:00
// mix buffers...
2009-12-18 05:47:48 -08:00
if ( outputsReady ( outputTracks ) ) {
2010-06-01 23:49:17 -07:00
mAudioMixer - > process ( ) ;
2009-12-18 05:47:48 -08:00
} else {
2010-06-01 23:49:17 -07:00
memset ( mMixBuffer , 0 , mixBufferSize ) ;
2009-12-18 05:47:48 -08:00
}
2009-09-22 00:35:48 -07:00
sleepTime = 0 ;
2009-10-05 20:29:18 -07:00
writeFrames = mFrameCount ;
2009-07-17 12:17:14 -07:00
} else {
2009-10-05 20:29:18 -07:00
if ( sleepTime = = 0 ) {
2009-11-09 23:32:22 -08:00
if ( mixerStatus = = MIXER_TRACKS_ENABLED ) {
sleepTime = activeSleepTime ;
} else {
sleepTime = idleSleepTime ;
}
2009-10-05 20:29:18 -07:00
} else if ( mBytesWritten ! = 0 ) {
// flush remaining overflow buffers in output tracks
for ( size_t i = 0 ; i < outputTracks . size ( ) ; i + + ) {
if ( outputTracks [ i ] - > isActive ( ) ) {
sleepTime = 0 ;
writeFrames = 0 ;
2010-06-01 23:49:17 -07:00
memset ( mMixBuffer , 0 , mixBufferSize ) ;
2009-10-05 20:29:18 -07:00
break ;
}
}
2009-07-17 12:17:14 -07:00
}
}
2009-09-22 00:35:48 -07:00
if ( mSuspended ) {
2010-08-18 18:13:17 -07:00
sleepTime = suspendSleepTimeUs ( ) ;
2009-09-22 00:35:48 -07:00
}
// sleepTime == 0 means we must write to audio hardware
if ( sleepTime = = 0 ) {
2010-06-01 23:49:17 -07:00
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
effectChains [ i ] - > process_l ( ) ;
}
// enable changes in effect chain
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2010-06-01 23:49:17 -07:00
2009-10-05 20:29:18 -07:00
standbyTime = systemTime ( ) + kStandbyTimeInNsecs ;
2009-09-22 00:35:48 -07:00
for ( size_t i = 0 ; i < outputTracks . size ( ) ; i + + ) {
2010-06-01 23:49:17 -07:00
outputTracks [ i ] - > write ( mMixBuffer , writeFrames ) ;
2009-07-17 12:17:14 -07:00
}
2009-09-22 00:35:48 -07:00
mStandby = false ;
mBytesWritten + = mixBufferSize ;
2009-07-17 12:17:14 -07:00
} else {
2010-06-01 23:49:17 -07:00
// enable changes in effect chain
2010-07-13 04:45:46 -07:00
unlockEffectChains ( effectChains ) ;
2009-09-22 00:35:48 -07:00
usleep ( sleepTime ) ;
2009-07-17 12:17:14 -07:00
}
2008-10-21 07:00:00 -07:00
2009-07-17 12:17:14 -07:00
// finally let go of all our tracks, without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove . clear ( ) ;
outputTracks . clear ( ) ;
2010-06-01 23:49:17 -07:00
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains . clear ( ) ;
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
2011-07-22 09:04:31 -07:00
releaseWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
return false ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : DuplicatingThread : : addOutputTrack ( MixerThread * thread )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
int frameCount = ( 3 * mFrameCount * mSampleRate ) / thread - > sampleRate ( ) ;
OutputTrack * outputTrack = new OutputTrack ( ( ThreadBase * ) thread ,
2009-12-18 05:47:48 -08:00
this ,
2009-07-17 12:17:14 -07:00
mSampleRate ,
mFormat ,
2011-05-24 15:53:33 -07:00
mChannelMask ,
2009-07-17 12:17:14 -07:00
frameCount ) ;
2009-08-10 23:22:32 -07:00
if ( outputTrack - > cblk ( ) ! = NULL ) {
2011-04-19 22:30:36 -07:00
thread - > setStreamVolume ( AUDIO_STREAM_CNT , 1.0f ) ;
2009-08-10 23:22:32 -07:00
mOutputTracks . add ( outputTrack ) ;
LOGV ( " addOutputTrack() track %p, on thread %p " , outputTrack , thread ) ;
2009-12-18 05:47:48 -08:00
updateWaitTime ( ) ;
2009-08-10 23:22:32 -07:00
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : DuplicatingThread : : removeOutputTrack ( MixerThread * thread )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
for ( size_t i = 0 ; i < mOutputTracks . size ( ) ; i + + ) {
if ( mOutputTracks [ i ] - > thread ( ) = = ( ThreadBase * ) thread ) {
2009-08-10 23:22:32 -07:00
mOutputTracks [ i ] - > destroy ( ) ;
2009-07-17 12:17:14 -07:00
mOutputTracks . removeAt ( i ) ;
2009-12-18 05:47:48 -08:00
updateWaitTime ( ) ;
2009-07-17 12:17:14 -07:00
return ;
}
}
LOGV ( " removeOutputTrack(): unkonwn thread: %p " , thread ) ;
2008-10-21 07:00:00 -07:00
}
2009-12-18 05:47:48 -08:00
void AudioFlinger : : DuplicatingThread : : updateWaitTime ( )
{
mWaitTimeMs = UINT_MAX ;
for ( size_t i = 0 ; i < mOutputTracks . size ( ) ; i + + ) {
sp < ThreadBase > strong = mOutputTracks [ i ] - > thread ( ) . promote ( ) ;
if ( strong ! = NULL ) {
uint32_t waitTimeMs = ( strong - > frameCount ( ) * 2 * 1000 ) / strong - > sampleRate ( ) ;
if ( waitTimeMs < mWaitTimeMs ) {
mWaitTimeMs = waitTimeMs ;
}
}
}
}
bool AudioFlinger : : DuplicatingThread : : outputsReady ( SortedVector < sp < OutputTrack > > & outputTracks )
{
for ( size_t i = 0 ; i < outputTracks . size ( ) ; i + + ) {
sp < ThreadBase > thread = outputTracks [ i ] - > thread ( ) . promote ( ) ;
if ( thread = = 0 ) {
LOGW ( " DuplicatingThread::outputsReady() could not promote thread on output track %p " , outputTracks [ i ] . get ( ) ) ;
return false ;
}
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
if ( playbackThread - > standby ( ) & & ! playbackThread - > isSuspended ( ) ) {
LOGV ( " DuplicatingThread output track %p on thread %p Not Ready " , outputTracks [ i ] . get ( ) , thread . get ( ) ) ;
return false ;
}
}
return true ;
}
uint32_t AudioFlinger : : DuplicatingThread : : activeSleepTimeUs ( )
{
return ( mWaitTimeMs * 1000 ) / 2 ;
}
2008-10-21 07:00:00 -07:00
// ----------------------------------------------------------------------------
2009-03-09 11:52:12 -07:00
// TrackBase constructor must be called with AudioFlinger::mLock held
2009-07-17 12:17:14 -07:00
AudioFlinger : : ThreadBase : : TrackBase : : TrackBase (
const wp < ThreadBase > & thread ,
2008-10-21 07:00:00 -07:00
const sp < Client > & client ,
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2008-12-17 18:05:43 -08:00
int frameCount ,
2009-03-03 19:31:44 -08:00
uint32_t flags ,
2010-06-01 23:49:17 -07:00
const sp < IMemory > & sharedBuffer ,
int sessionId )
2008-10-21 07:00:00 -07:00
: RefBase ( ) ,
2009-07-17 12:17:14 -07:00
mThread ( thread ) ,
2008-10-21 07:00:00 -07:00
mClient ( client ) ,
2009-09-09 05:16:08 -07:00
mCblk ( 0 ) ,
2008-12-17 18:05:43 -08:00
mFrameCount ( 0 ) ,
2008-10-21 07:00:00 -07:00
mState ( IDLE ) ,
2008-12-17 18:05:43 -08:00
mClientTid ( - 1 ) ,
mFormat ( format ) ,
2010-06-01 23:49:17 -07:00
mFlags ( flags & ~ SYSTEM_FLAGS_MASK ) ,
mSessionId ( sessionId )
2008-10-21 07:00:00 -07:00
{
2008-12-17 18:05:43 -08:00
LOGV_IF ( sharedBuffer ! = 0 , " sharedBuffer: %p, size: %d " , sharedBuffer - > pointer ( ) , sharedBuffer - > size ( ) ) ;
2008-10-21 07:00:00 -07:00
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
2008-12-17 18:05:43 -08:00
size_t size = sizeof ( audio_track_cblk_t ) ;
2011-05-24 15:53:33 -07:00
uint8_t channelCount = popcount ( channelMask ) ;
2008-12-17 18:05:43 -08:00
size_t bufferSize = frameCount * channelCount * sizeof ( int16_t ) ;
if ( sharedBuffer = = 0 ) {
size + = bufferSize ;
}
2009-03-03 19:31:44 -08:00
if ( client ! = NULL ) {
mCblkMemory = client - > heap ( ) - > allocate ( size ) ;
if ( mCblkMemory ! = 0 ) {
mCblk = static_cast < audio_track_cblk_t * > ( mCblkMemory - > pointer ( ) ) ;
if ( mCblk ) { // construct the shared structure in-place.
new ( mCblk ) audio_track_cblk_t ( ) ;
// clear all buffers
mCblk - > frameCount = frameCount ;
2009-07-07 07:10:45 -07:00
mCblk - > sampleRate = sampleRate ;
2011-05-24 15:53:33 -07:00
mChannelCount = channelCount ;
mChannelMask = channelMask ;
2009-03-03 19:31:44 -08:00
if ( sharedBuffer = = 0 ) {
mBuffer = ( char * ) mCblk + sizeof ( audio_track_cblk_t ) ;
memset ( mBuffer , 0 , frameCount * channelCount * sizeof ( int16_t ) ) ;
// Force underrun condition to avoid false underrun callback until first data is
2010-09-30 16:12:31 -07:00
// written to buffer (other flags are cleared)
2010-05-14 03:26:45 -07:00
mCblk - > flags = CBLK_UNDERRUN_ON ;
2009-03-03 19:31:44 -08:00
} else {
mBuffer = sharedBuffer - > pointer ( ) ;
}
mBufferEnd = ( uint8_t * ) mBuffer + bufferSize ;
2008-12-17 18:05:43 -08:00
}
2009-03-03 19:31:44 -08:00
} else {
LOGE ( " not enough memory for AudioTrack size=%u " , size ) ;
client - > heap ( ) - > dump ( " AudioTrack " ) ;
return ;
}
} else {
mCblk = ( audio_track_cblk_t * ) ( new uint8_t [ size ] ) ;
if ( mCblk ) { // construct the shared structure in-place.
new ( mCblk ) audio_track_cblk_t ( ) ;
// clear all buffers
mCblk - > frameCount = frameCount ;
2009-07-07 07:10:45 -07:00
mCblk - > sampleRate = sampleRate ;
2011-05-24 15:53:33 -07:00
mChannelCount = channelCount ;
mChannelMask = channelMask ;
2009-03-03 19:31:44 -08:00
mBuffer = ( char * ) mCblk + sizeof ( audio_track_cblk_t ) ;
memset ( mBuffer , 0 , frameCount * channelCount * sizeof ( int16_t ) ) ;
// Force underrun condition to avoid false underrun callback until first data is
2010-09-30 16:12:31 -07:00
// written to buffer (other flags are cleared)
2010-05-14 03:26:45 -07:00
mCblk - > flags = CBLK_UNDERRUN_ON ;
2009-03-03 19:31:44 -08:00
mBufferEnd = ( uint8_t * ) mBuffer + bufferSize ;
}
}
2008-10-21 07:00:00 -07:00
}
2009-09-16 06:02:45 -07:00
AudioFlinger : : ThreadBase : : TrackBase : : ~ TrackBase ( )
2008-10-21 07:00:00 -07:00
{
2009-03-03 19:31:44 -08:00
if ( mCblk ) {
2009-07-17 12:17:14 -07:00
mCblk - > ~ audio_track_cblk_t ( ) ; // destroy our shared-structure.
if ( mClient = = NULL ) {
delete mCblk ;
}
2009-03-03 19:31:44 -08:00
}
2008-10-21 07:00:00 -07:00
mCblkMemory . clear ( ) ; // and free the shared memory
2009-09-17 05:12:56 -07:00
if ( mClient ! = NULL ) {
Mutex : : Autolock _l ( mClient - > audioFlinger ( ) - > mLock ) ;
mClient . clear ( ) ;
}
2008-10-21 07:00:00 -07:00
}
2009-09-16 06:02:45 -07:00
void AudioFlinger : : ThreadBase : : TrackBase : : releaseBuffer ( AudioBufferProvider : : Buffer * buffer )
2008-10-21 07:00:00 -07:00
{
buffer - > raw = 0 ;
2008-12-17 18:05:43 -08:00
mFrameCount = buffer - > frameCount ;
2008-10-21 07:00:00 -07:00
step ( ) ;
2008-12-17 18:05:43 -08:00
buffer - > frameCount = 0 ;
2008-10-21 07:00:00 -07:00
}
2009-09-16 06:02:45 -07:00
bool AudioFlinger : : ThreadBase : : TrackBase : : step ( ) {
2008-10-21 07:00:00 -07:00
bool result ;
audio_track_cblk_t * cblk = this - > cblk ( ) ;
2008-12-17 18:05:43 -08:00
result = cblk - > stepServer ( mFrameCount ) ;
2008-10-21 07:00:00 -07:00
if ( ! result ) {
LOGV ( " stepServer failed acquiring cblk mutex " ) ;
mFlags | = STEPSERVER_FAILED ;
}
return result ;
}
2009-09-16 06:02:45 -07:00
void AudioFlinger : : ThreadBase : : TrackBase : : reset ( ) {
2008-10-21 07:00:00 -07:00
audio_track_cblk_t * cblk = this - > cblk ( ) ;
cblk - > user = 0 ;
cblk - > server = 0 ;
2008-12-17 18:05:43 -08:00
cblk - > userBase = 0 ;
cblk - > serverBase = 0 ;
2009-03-03 19:31:44 -08:00
mFlags & = ( uint32_t ) ( ~ SYSTEM_FLAGS_MASK ) ;
2008-12-17 18:05:43 -08:00
LOGV ( " TrackBase::reset " ) ;
2008-10-21 07:00:00 -07:00
}
2009-09-16 06:02:45 -07:00
sp < IMemory > AudioFlinger : : ThreadBase : : TrackBase : : getCblk ( ) const
2008-10-21 07:00:00 -07:00
{
return mCblkMemory ;
}
2009-09-16 06:02:45 -07:00
int AudioFlinger : : ThreadBase : : TrackBase : : sampleRate ( ) const {
2009-03-18 17:39:46 -07:00
return ( int ) mCblk - > sampleRate ;
2008-10-21 07:00:00 -07:00
}
2009-09-16 06:02:45 -07:00
int AudioFlinger : : ThreadBase : : TrackBase : : channelCount ( ) const {
2011-05-24 15:53:33 -07:00
return ( const int ) mChannelCount ;
}
uint32_t AudioFlinger : : ThreadBase : : TrackBase : : channelMask ( ) const {
return mChannelMask ;
2008-12-17 18:05:43 -08:00
}
2009-09-16 06:02:45 -07:00
void * AudioFlinger : : ThreadBase : : TrackBase : : getBuffer ( uint32_t offset , uint32_t frames ) const {
2008-12-17 18:05:43 -08:00
audio_track_cblk_t * cblk = this - > cblk ( ) ;
2009-07-17 12:17:14 -07:00
int8_t * bufferStart = ( int8_t * ) mBuffer + ( offset - cblk - > serverBase ) * cblk - > frameSize ;
int8_t * bufferEnd = bufferStart + frames * cblk - > frameSize ;
2008-12-17 18:05:43 -08:00
// Check validity of returned pointer in case the track control block would have been corrupted.
2009-07-17 12:17:14 -07:00
if ( bufferStart < mBuffer | | bufferStart > bufferEnd | | bufferEnd > mBufferEnd | |
( ( unsigned long ) bufferStart & ( unsigned long ) ( cblk - > frameSize - 1 ) ) ) {
2009-03-18 17:39:46 -07:00
LOGE ( " TrackBase::getBuffer buffer out of range: \n start: %p, end %p , mBuffer %p mBufferEnd %p \n \
2011-05-24 15:53:33 -07:00
server % d , serverBase % d , user % d , userBase % d " ,
2008-12-17 18:05:43 -08:00
bufferStart , bufferEnd , mBuffer , mBufferEnd ,
2011-05-24 15:53:33 -07:00
cblk - > server , cblk - > serverBase , cblk - > user , cblk - > userBase ) ;
2008-12-17 18:05:43 -08:00
return 0 ;
}
return bufferStart ;
}
2008-10-21 07:00:00 -07:00
// ----------------------------------------------------------------------------
2009-07-17 12:17:14 -07:00
// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
AudioFlinger : : PlaybackThread : : Track : : Track (
const wp < ThreadBase > & thread ,
2008-10-21 07:00:00 -07:00
const sp < Client > & client ,
int streamType ,
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2008-12-17 18:05:43 -08:00
int frameCount ,
2010-06-01 23:49:17 -07:00
const sp < IMemory > & sharedBuffer ,
int sessionId )
2011-05-24 15:53:33 -07:00
: TrackBase ( thread , client , sampleRate , format , channelMask , frameCount , 0 , sharedBuffer , sessionId ) ,
2010-08-31 13:50:07 -07:00
mMute ( false ) , mSharedBuffer ( sharedBuffer ) , mName ( - 1 ) , mMainBuffer ( NULL ) , mAuxBuffer ( NULL ) ,
mAuxEffectId ( 0 ) , mHasVolumeController ( false )
2008-10-21 07:00:00 -07:00
{
2009-09-09 05:16:08 -07:00
if ( mCblk ! = NULL ) {
sp < ThreadBase > baseThread = thread . promote ( ) ;
if ( baseThread ! = 0 ) {
PlaybackThread * playbackThread = ( PlaybackThread * ) baseThread . get ( ) ;
mName = playbackThread - > getTrackName_l ( ) ;
2010-06-01 23:49:17 -07:00
mMainBuffer = playbackThread - > mixBuffer ( ) ;
2009-09-09 05:16:08 -07:00
}
LOGV ( " Track constructor name %d, calling thread %d " , mName , IPCThreadState : : self ( ) - > getCallingPid ( ) ) ;
if ( mName < 0 ) {
LOGE ( " no more track names available " ) ;
}
mVolume [ 0 ] = 1.0f ;
mVolume [ 1 ] = 1.0f ;
mStreamType = streamType ;
// NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
2011-07-21 19:35:01 -07:00
mCblk - > frameSize = audio_is_linear_pcm ( format ) ? mChannelCount * sizeof ( int16_t ) : sizeof ( uint8_t ) ;
2009-07-17 12:17:14 -07:00
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
AudioFlinger : : PlaybackThread : : Track : : ~ Track ( )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
LOGV ( " PlaybackThread::Track destructor " ) ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2009-12-01 02:17:41 -08:00
Mutex : : Autolock _l ( thread - > mLock ) ;
2009-07-17 12:17:14 -07:00
mState = TERMINATED ;
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : destroy ( )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
// NOTE: destroyTrack_l() can remove a strong reference to this Track
2009-03-09 11:52:12 -07:00
// by removing it from mTracks vector, so there is a risk that this Tracks's
2009-07-17 12:17:14 -07:00
// desctructor is called. As the destructor needs to lock mLock,
// we must acquire a strong reference on this Track before locking mLock
2009-03-09 11:52:12 -07:00
// here so that the destructor is called only when exiting this function.
2009-07-17 12:17:14 -07:00
// On the other hand, as long as Track::destroy() is only called by
// TrackHandle destructor, the TrackHandle still holds a strong ref on
2009-03-09 11:52:12 -07:00
// this Track with its member mTrack.
sp < Track > keep ( this ) ;
2009-07-17 12:17:14 -07:00
{ // scope for mLock
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2009-12-01 02:17:41 -08:00
if ( ! isOutputTrack ( ) ) {
if ( mState = = ACTIVE | | mState = = RESUMING ) {
2010-07-13 04:45:46 -07:00
AudioSystem : : stopOutput ( thread - > id ( ) ,
2011-04-19 22:30:36 -07:00
( audio_stream_type_t ) mStreamType ,
2010-07-13 04:45:46 -07:00
mSessionId ) ;
2011-02-24 14:51:45 -08:00
// to track the speaker usage
addBatteryData ( IMediaPlayerService : : kBatteryDataAudioFlingerStop ) ;
2009-12-01 02:17:41 -08:00
}
AudioSystem : : releaseOutput ( thread - > id ( ) ) ;
2009-11-19 09:00:56 -08:00
}
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( thread - > mLock ) ;
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
playbackThread - > destroyTrack_l ( this ) ;
}
2009-03-09 11:52:12 -07:00
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : dump ( char * buffer , size_t size )
2008-10-21 07:00:00 -07:00
{
2011-05-24 15:53:33 -07:00
snprintf ( buffer , size , " %05d %05d %03u %03u 0x%08x %05u %04u %1d %1d %1d %05u %05u %05u 0x%08x 0x%08x 0x%08x 0x%08x \n " ,
2008-10-21 07:00:00 -07:00
mName - AudioMixer : : TRACK0 ,
2009-03-03 19:31:44 -08:00
( mClient = = NULL ) ? getpid ( ) : mClient - > pid ( ) ,
2008-10-21 07:00:00 -07:00
mStreamType ,
mFormat ,
2011-05-24 15:53:33 -07:00
mChannelMask ,
2010-06-01 23:49:17 -07:00
mSessionId ,
2008-12-17 18:05:43 -08:00
mFrameCount ,
2008-10-21 07:00:00 -07:00
mState ,
mMute ,
mFillingUpStatus ,
mCblk - > sampleRate ,
mCblk - > volume [ 0 ] ,
mCblk - > volume [ 1 ] ,
mCblk - > server ,
2010-06-01 23:49:17 -07:00
mCblk - > user ,
( int ) mMainBuffer ,
( int ) mAuxBuffer ) ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : Track : : getNextBuffer ( AudioBufferProvider : : Buffer * buffer )
2008-10-21 07:00:00 -07:00
{
audio_track_cblk_t * cblk = this - > cblk ( ) ;
2008-12-17 18:05:43 -08:00
uint32_t framesReady ;
uint32_t framesReq = buffer - > frameCount ;
// Check if last stepServer failed, try to step now
2008-10-21 07:00:00 -07:00
if ( mFlags & TrackBase : : STEPSERVER_FAILED ) {
if ( ! step ( ) ) goto getNextBuffer_exit ;
LOGV ( " stepServer recovered " ) ;
mFlags & = ~ TrackBase : : STEPSERVER_FAILED ;
}
2008-12-17 18:05:43 -08:00
framesReady = cblk - > framesReady ( ) ;
if ( LIKELY ( framesReady ) ) {
uint32_t s = cblk - > server ;
uint32_t bufferEnd = cblk - > serverBase + cblk - > frameCount ;
bufferEnd = ( cblk - > loopEnd < bufferEnd ) ? cblk - > loopEnd : bufferEnd ;
if ( framesReq > framesReady ) {
framesReq = framesReady ;
}
if ( s + framesReq > bufferEnd ) {
framesReq = bufferEnd - s ;
}
buffer - > raw = getBuffer ( s , framesReq ) ;
if ( buffer - > raw = = 0 ) goto getNextBuffer_exit ;
buffer - > frameCount = framesReq ;
return NO_ERROR ;
2008-10-21 07:00:00 -07:00
}
2008-12-17 18:05:43 -08:00
2008-10-21 07:00:00 -07:00
getNextBuffer_exit :
buffer - > raw = 0 ;
buffer - > frameCount = 0 ;
2009-10-05 20:29:18 -07:00
LOGV ( " getNextBuffer() no more data for track %d on thread %p " , mName , mThread . unsafe_get ( ) ) ;
2008-10-21 07:00:00 -07:00
return NOT_ENOUGH_DATA ;
}
2009-07-17 12:17:14 -07:00
bool AudioFlinger : : PlaybackThread : : Track : : isReady ( ) const {
2010-10-05 14:41:42 -07:00
if ( mFillingUpStatus ! = FS_FILLING | | isStopped ( ) | | isPausing ( ) ) return true ;
2008-12-17 18:05:43 -08:00
if ( mCblk - > framesReady ( ) > = mCblk - > frameCount | |
2010-05-14 03:26:45 -07:00
( mCblk - > flags & CBLK_FORCEREADY_MSK ) ) {
2008-10-21 07:00:00 -07:00
mFillingUpStatus = FS_FILLED ;
2011-03-28 18:37:07 -07:00
android_atomic_and ( ~ CBLK_FORCEREADY_MSK , & mCblk - > flags ) ;
2008-10-21 07:00:00 -07:00
return true ;
}
return false ;
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : Track : : start ( )
2008-10-21 07:00:00 -07:00
{
2009-11-19 09:00:56 -08:00
status_t status = NO_ERROR ;
2010-07-19 06:24:46 -07:00
LOGV ( " start(%d), calling thread %d session %d " ,
mName , IPCThreadState : : self ( ) - > getCallingPid ( ) , mSessionId ) ;
2009-07-17 12:17:14 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
Mutex : : Autolock _l ( thread - > mLock ) ;
2009-11-19 09:00:56 -08:00
int state = mState ;
// here the track could be either new, or restarted
// in both cases "unstop" the track
if ( mState = = PAUSED ) {
mState = TrackBase : : RESUMING ;
LOGV ( " PAUSED => RESUMING (%d) on thread %p " , mName , this ) ;
} else {
mState = TrackBase : : ACTIVE ;
LOGV ( " ? => ACTIVE (%d) on thread %p " , mName , this ) ;
}
if ( ! isOutputTrack ( ) & & state ! = ACTIVE & & state ! = RESUMING ) {
thread - > mLock . unlock ( ) ;
2010-07-13 04:45:46 -07:00
status = AudioSystem : : startOutput ( thread - > id ( ) ,
2011-04-19 22:30:36 -07:00
( audio_stream_type_t ) mStreamType ,
2010-07-13 04:45:46 -07:00
mSessionId ) ;
2009-11-19 09:00:56 -08:00
thread - > mLock . lock ( ) ;
2011-02-24 14:51:45 -08:00
// to track the speaker usage
if ( status = = NO_ERROR ) {
addBatteryData ( IMediaPlayerService : : kBatteryDataAudioFlingerStart ) ;
}
2009-11-19 09:00:56 -08:00
}
if ( status = = NO_ERROR ) {
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
playbackThread - > addTrack_l ( this ) ;
} else {
mState = state ;
}
} else {
status = BAD_VALUE ;
2009-07-17 12:17:14 -07:00
}
2009-11-19 09:00:56 -08:00
return status ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : stop ( )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
LOGV ( " stop(%d), calling thread %d " , mName , IPCThreadState : : self ( ) - > getCallingPid ( ) ) ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
Mutex : : Autolock _l ( thread - > mLock ) ;
2009-11-19 09:00:56 -08:00
int state = mState ;
2009-07-17 12:17:14 -07:00
if ( mState > STOPPED ) {
mState = STOPPED ;
// If the track is not active (PAUSED and buffers full), flush buffers
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
if ( playbackThread - > mActiveTracks . indexOf ( this ) < 0 ) {
reset ( ) ;
}
2009-10-05 20:29:18 -07:00
LOGV ( " (> STOPPED) => STOPPED (%d) on thread %p " , mName , playbackThread ) ;
2008-10-21 07:00:00 -07:00
}
2009-11-19 09:00:56 -08:00
if ( ! isOutputTrack ( ) & & ( state = = ACTIVE | | state = = RESUMING ) ) {
thread - > mLock . unlock ( ) ;
2010-07-13 04:45:46 -07:00
AudioSystem : : stopOutput ( thread - > id ( ) ,
2011-04-19 22:30:36 -07:00
( audio_stream_type_t ) mStreamType ,
2010-07-13 04:45:46 -07:00
mSessionId ) ;
2009-11-19 09:00:56 -08:00
thread - > mLock . lock ( ) ;
2011-02-24 14:51:45 -08:00
// to track the speaker usage
addBatteryData ( IMediaPlayerService : : kBatteryDataAudioFlingerStop ) ;
2009-11-19 09:00:56 -08:00
}
2008-10-21 07:00:00 -07:00
}
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : pause ( )
2008-10-21 07:00:00 -07:00
{
2009-03-03 19:31:44 -08:00
LOGV ( " pause(%d), calling thread %d " , mName , IPCThreadState : : self ( ) - > getCallingPid ( ) ) ;
2009-07-17 12:17:14 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
Mutex : : Autolock _l ( thread - > mLock ) ;
if ( mState = = ACTIVE | | mState = = RESUMING ) {
mState = PAUSING ;
2009-10-05 20:29:18 -07:00
LOGV ( " ACTIVE/RESUMING => PAUSING (%d) on thread %p " , mName , thread . get ( ) ) ;
2009-11-19 09:00:56 -08:00
if ( ! isOutputTrack ( ) ) {
thread - > mLock . unlock ( ) ;
2010-07-13 04:45:46 -07:00
AudioSystem : : stopOutput ( thread - > id ( ) ,
2011-04-19 22:30:36 -07:00
( audio_stream_type_t ) mStreamType ,
2010-07-13 04:45:46 -07:00
mSessionId ) ;
2009-11-19 09:00:56 -08:00
thread - > mLock . lock ( ) ;
2011-02-24 14:51:45 -08:00
// to track the speaker usage
addBatteryData ( IMediaPlayerService : : kBatteryDataAudioFlingerStop ) ;
2009-11-19 09:00:56 -08:00
}
2009-07-17 12:17:14 -07:00
}
2008-10-21 07:00:00 -07:00
}
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : flush ( )
2008-10-21 07:00:00 -07:00
{
LOGV ( " flush(%d) " , mName ) ;
2009-07-17 12:17:14 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
Mutex : : Autolock _l ( thread - > mLock ) ;
if ( mState ! = STOPPED & & mState ! = PAUSED & & mState ! = PAUSING ) {
return ;
}
// No point remaining in PAUSED state after a flush => go to
// STOPPED state
mState = STOPPED ;
2008-10-21 07:00:00 -07:00
2011-03-28 18:37:07 -07:00
// do not reset the track if it is still in the process of being stopped or paused.
// this will be done by prepareTracks_l() when the track is stopped.
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
if ( playbackThread - > mActiveTracks . indexOf ( this ) < 0 ) {
reset ( ) ;
}
2009-07-17 12:17:14 -07:00
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : reset ( )
2008-10-21 07:00:00 -07:00
{
2008-12-17 18:05:43 -08:00
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
if ( ! mResetDone ) {
TrackBase : : reset ( ) ;
// Force underrun condition to avoid false underrun callback until first data is
// written to buffer
2011-03-28 18:37:07 -07:00
android_atomic_and ( ~ CBLK_FORCEREADY_MSK , & mCblk - > flags ) ;
android_atomic_or ( CBLK_UNDERRUN_ON , & mCblk - > flags ) ;
2009-07-17 12:17:14 -07:00
mFillingUpStatus = FS_FILLING ;
2008-12-17 18:05:43 -08:00
mResetDone = true ;
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : mute ( bool muted )
2008-10-21 07:00:00 -07:00
{
mMute = muted ;
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : Track : : setVolume ( float left , float right )
2008-10-21 07:00:00 -07:00
{
mVolume [ 0 ] = left ;
mVolume [ 1 ] = right ;
}
2010-06-01 23:49:17 -07:00
status_t AudioFlinger : : PlaybackThread : : Track : : attachAuxEffect ( int EffectId )
{
status_t status = DEAD_OBJECT ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . get ( ) ;
status = playbackThread - > attachAuxEffect ( this , EffectId ) ;
}
return status ;
}
void AudioFlinger : : PlaybackThread : : Track : : setAuxBuffer ( int EffectId , int32_t * buffer )
{
mAuxEffectId = EffectId ;
mAuxBuffer = buffer ;
}
2008-10-21 07:00:00 -07:00
// ----------------------------------------------------------------------------
2009-03-09 11:52:12 -07:00
// RecordTrack constructor must be called with AudioFlinger::mLock held
2009-07-17 12:17:14 -07:00
AudioFlinger : : RecordThread : : RecordTrack : : RecordTrack (
const wp < ThreadBase > & thread ,
2009-03-03 19:31:44 -08:00
const sp < Client > & client ,
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2009-03-03 19:31:44 -08:00
int frameCount ,
2010-06-01 23:49:17 -07:00
uint32_t flags ,
int sessionId )
2009-07-17 12:17:14 -07:00
: TrackBase ( thread , client , sampleRate , format ,
2011-05-24 15:53:33 -07:00
channelMask , frameCount , flags , 0 , sessionId ) ,
2009-07-17 12:17:14 -07:00
mOverflow ( false )
2009-03-03 19:31:44 -08:00
{
2009-09-09 05:16:08 -07:00
if ( mCblk ! = NULL ) {
LOGV ( " RecordTrack constructor, size %d " , ( int ) mBufferEnd - ( int ) mBuffer ) ;
2011-04-19 22:30:36 -07:00
if ( format = = AUDIO_FORMAT_PCM_16_BIT ) {
2011-05-24 15:53:33 -07:00
mCblk - > frameSize = mChannelCount * sizeof ( int16_t ) ;
2011-04-19 22:30:36 -07:00
} else if ( format = = AUDIO_FORMAT_PCM_8_BIT ) {
2011-05-24 15:53:33 -07:00
mCblk - > frameSize = mChannelCount * sizeof ( int8_t ) ;
2009-09-09 05:16:08 -07:00
} else {
mCblk - > frameSize = sizeof ( int8_t ) ;
}
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
AudioFlinger : : RecordThread : : RecordTrack : : ~ RecordTrack ( )
2009-03-03 19:31:44 -08:00
{
2009-11-19 09:00:56 -08:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
AudioSystem : : releaseInput ( thread - > id ( ) ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : RecordThread : : RecordTrack : : getNextBuffer ( AudioBufferProvider : : Buffer * buffer )
2009-03-03 19:31:44 -08:00
{
audio_track_cblk_t * cblk = this - > cblk ( ) ;
uint32_t framesAvail ;
uint32_t framesReq = buffer - > frameCount ;
// Check if last stepServer failed, try to step now
if ( mFlags & TrackBase : : STEPSERVER_FAILED ) {
if ( ! step ( ) ) goto getNextBuffer_exit ;
LOGV ( " stepServer recovered " ) ;
mFlags & = ~ TrackBase : : STEPSERVER_FAILED ;
}
framesAvail = cblk - > framesAvailable_l ( ) ;
if ( LIKELY ( framesAvail ) ) {
uint32_t s = cblk - > server ;
uint32_t bufferEnd = cblk - > serverBase + cblk - > frameCount ;
if ( framesReq > framesAvail ) {
framesReq = framesAvail ;
}
if ( s + framesReq > bufferEnd ) {
framesReq = bufferEnd - s ;
}
buffer - > raw = getBuffer ( s , framesReq ) ;
if ( buffer - > raw = = 0 ) goto getNextBuffer_exit ;
buffer - > frameCount = framesReq ;
return NO_ERROR ;
}
getNextBuffer_exit :
buffer - > raw = 0 ;
buffer - > frameCount = 0 ;
return NOT_ENOUGH_DATA ;
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : RecordThread : : RecordTrack : : start ( )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
RecordThread * recordThread = ( RecordThread * ) thread . get ( ) ;
return recordThread - > start ( this ) ;
2009-11-19 09:00:56 -08:00
} else {
return BAD_VALUE ;
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : RecordThread : : RecordTrack : : stop ( )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
RecordThread * recordThread = ( RecordThread * ) thread . get ( ) ;
recordThread - > stop ( this ) ;
2011-03-28 18:37:07 -07:00
TrackBase : : reset ( ) ;
// Force overerrun condition to avoid false overrun callback until first data is
// read from buffer
android_atomic_or ( CBLK_UNDERRUN_ON , & mCblk - > flags ) ;
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
}
2009-11-07 00:01:32 -08:00
void AudioFlinger : : RecordThread : : RecordTrack : : dump ( char * buffer , size_t size )
{
2011-05-24 15:53:33 -07:00
snprintf ( buffer , size , " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x \n " ,
2009-11-07 00:01:32 -08:00
( mClient = = NULL ) ? getpid ( ) : mClient - > pid ( ) ,
mFormat ,
2011-05-24 15:53:33 -07:00
mChannelMask ,
2010-06-01 23:49:17 -07:00
mSessionId ,
2009-11-07 00:01:32 -08:00
mFrameCount ,
mState ,
mCblk - > sampleRate ,
mCblk - > server ,
mCblk - > user ) ;
}
2009-03-03 19:31:44 -08:00
// ----------------------------------------------------------------------------
2009-07-17 12:17:14 -07:00
AudioFlinger : : PlaybackThread : : OutputTrack : : OutputTrack (
const wp < ThreadBase > & thread ,
2009-12-18 05:47:48 -08:00
DuplicatingThread * sourceThread ,
2009-03-03 19:31:44 -08:00
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2009-03-03 19:31:44 -08:00
int frameCount )
2011-05-24 15:53:33 -07:00
: Track ( thread , NULL , AUDIO_STREAM_CNT , sampleRate , format , channelMask , frameCount , NULL , 0 ) ,
2009-12-18 05:47:48 -08:00
mActive ( false ) , mSourceThread ( sourceThread )
2009-03-03 19:31:44 -08:00
{
2009-07-17 12:17:14 -07:00
PlaybackThread * playbackThread = ( PlaybackThread * ) thread . unsafe_get ( ) ;
2009-08-10 23:22:32 -07:00
if ( mCblk ! = NULL ) {
2010-05-14 03:26:45 -07:00
mCblk - > flags | = CBLK_DIRECTION_OUT ;
2009-08-10 23:22:32 -07:00
mCblk - > buffers = ( char * ) mCblk + sizeof ( audio_track_cblk_t ) ;
mCblk - > volume [ 0 ] = mCblk - > volume [ 1 ] = 0x1000 ;
mOutBuffer . frameCount = 0 ;
playbackThread - > mTracks . add ( this ) ;
2011-05-24 15:53:33 -07:00
LOGV ( " OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, " \
" mCblk->frameCount %d, mCblk->sampleRate %d, mChannelMask 0x%08x mBufferEnd %p " ,
mCblk , mBuffer , mCblk - > buffers ,
mCblk - > frameCount , mCblk - > sampleRate , mChannelMask , mBufferEnd ) ;
2009-08-10 23:22:32 -07:00
} else {
LOGW ( " Error creating output track on thread %p " , playbackThread ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
AudioFlinger : : PlaybackThread : : OutputTrack : : ~ OutputTrack ( )
2009-03-03 19:31:44 -08:00
{
2009-08-10 23:22:32 -07:00
clearBufferQueue ( ) ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : OutputTrack : : start ( )
2009-03-03 19:31:44 -08:00
{
status_t status = Track : : start ( ) ;
2009-07-17 12:17:14 -07:00
if ( status ! = NO_ERROR ) {
return status ;
}
mActive = true ;
2009-03-03 19:31:44 -08:00
mRetryCount = 127 ;
return status ;
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : OutputTrack : : stop ( )
2009-03-03 19:31:44 -08:00
{
Track : : stop ( ) ;
clearBufferQueue ( ) ;
mOutBuffer . frameCount = 0 ;
2009-07-17 12:17:14 -07:00
mActive = false ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
bool AudioFlinger : : PlaybackThread : : OutputTrack : : write ( int16_t * data , uint32_t frames )
2009-03-03 19:31:44 -08:00
{
Buffer * pInBuffer ;
Buffer inBuffer ;
2011-05-24 15:53:33 -07:00
uint32_t channelCount = mChannelCount ;
2009-07-17 12:17:14 -07:00
bool outputBufferFull = false ;
2009-03-03 19:31:44 -08:00
inBuffer . frameCount = frames ;
inBuffer . i16 = data ;
2009-07-17 12:17:14 -07:00
2009-12-18 05:47:48 -08:00
uint32_t waitTimeLeftMs = mSourceThread - > waitTimeMs ( ) ;
2009-07-17 12:17:14 -07:00
2009-10-05 20:29:18 -07:00
if ( ! mActive & & frames ! = 0 ) {
2009-07-17 12:17:14 -07:00
start ( ) ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
MixerThread * mixerThread = ( MixerThread * ) thread . get ( ) ;
if ( mCblk - > frameCount > frames ) {
if ( mBufferQueue . size ( ) < kMaxOverFlowBuffers ) {
uint32_t startFrames = ( mCblk - > frameCount - frames ) ;
pInBuffer = new Buffer ;
2010-05-14 05:45:46 -07:00
pInBuffer - > mBuffer = new int16_t [ startFrames * channelCount ] ;
2009-07-17 12:17:14 -07:00
pInBuffer - > frameCount = startFrames ;
pInBuffer - > i16 = pInBuffer - > mBuffer ;
2010-05-14 05:45:46 -07:00
memset ( pInBuffer - > raw , 0 , startFrames * channelCount * sizeof ( int16_t ) ) ;
2009-07-17 12:17:14 -07:00
mBufferQueue . add ( pInBuffer ) ;
} else {
LOGW ( " OutputTrack::write() %p no more buffers in queue " , this ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
while ( waitTimeLeftMs ) {
2009-03-03 19:31:44 -08:00
// First write pending buffers, then new data
if ( mBufferQueue . size ( ) ) {
pInBuffer = mBufferQueue . itemAt ( 0 ) ;
} else {
pInBuffer = & inBuffer ;
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
if ( pInBuffer - > frameCount = = 0 ) {
break ;
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
if ( mOutBuffer . frameCount = = 0 ) {
mOutBuffer . frameCount = pInBuffer - > frameCount ;
2009-07-17 12:17:14 -07:00
nsecs_t startTime = systemTime ( ) ;
if ( obtainBuffer ( & mOutBuffer , waitTimeLeftMs ) = = ( status_t ) AudioTrack : : NO_MORE_BUFFERS ) {
2009-12-18 05:47:48 -08:00
LOGV ( " OutputTrack::write() %p thread %p no more output buffers " , this , mThread . unsafe_get ( ) ) ;
2009-07-17 12:17:14 -07:00
outputBufferFull = true ;
2009-03-03 19:31:44 -08:00
break ;
}
2009-07-17 12:17:14 -07:00
uint32_t waitTimeMs = ( uint32_t ) ns2ms ( systemTime ( ) - startTime ) ;
if ( waitTimeLeftMs > = waitTimeMs ) {
waitTimeLeftMs - = waitTimeMs ;
} else {
waitTimeLeftMs = 0 ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
uint32_t outFrames = pInBuffer - > frameCount > mOutBuffer . frameCount ? mOutBuffer . frameCount : pInBuffer - > frameCount ;
2010-05-14 05:45:46 -07:00
memcpy ( mOutBuffer . raw , pInBuffer - > raw , outFrames * channelCount * sizeof ( int16_t ) ) ;
2009-03-03 19:31:44 -08:00
mCblk - > stepUser ( outFrames ) ;
pInBuffer - > frameCount - = outFrames ;
2010-05-14 05:45:46 -07:00
pInBuffer - > i16 + = outFrames * channelCount ;
2009-03-03 19:31:44 -08:00
mOutBuffer . frameCount - = outFrames ;
2010-05-14 05:45:46 -07:00
mOutBuffer . i16 + = outFrames * channelCount ;
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
if ( pInBuffer - > frameCount = = 0 ) {
if ( mBufferQueue . size ( ) ) {
mBufferQueue . removeAt ( 0 ) ;
delete [ ] pInBuffer - > mBuffer ;
delete pInBuffer ;
2009-12-18 05:47:48 -08:00
LOGV ( " OutputTrack::write() %p thread %p released overflow buffer %d " , this , mThread . unsafe_get ( ) , mBufferQueue . size ( ) ) ;
2009-03-03 19:31:44 -08:00
} else {
break ;
}
}
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
// If we could not write all frames, allocate a buffer and queue it for next time.
if ( inBuffer . frameCount ) {
2009-12-18 05:47:48 -08:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 & & ! thread - > standby ( ) ) {
if ( mBufferQueue . size ( ) < kMaxOverFlowBuffers ) {
pInBuffer = new Buffer ;
2010-05-14 05:45:46 -07:00
pInBuffer - > mBuffer = new int16_t [ inBuffer . frameCount * channelCount ] ;
2009-12-18 05:47:48 -08:00
pInBuffer - > frameCount = inBuffer . frameCount ;
pInBuffer - > i16 = pInBuffer - > mBuffer ;
2010-05-14 05:45:46 -07:00
memcpy ( pInBuffer - > raw , inBuffer . raw , inBuffer . frameCount * channelCount * sizeof ( int16_t ) ) ;
2009-12-18 05:47:48 -08:00
mBufferQueue . add ( pInBuffer ) ;
LOGV ( " OutputTrack::write() %p thread %p adding overflow buffer %d " , this , mThread . unsafe_get ( ) , mBufferQueue . size ( ) ) ;
} else {
LOGW ( " OutputTrack::write() %p thread %p no more overflow buffers " , mThread . unsafe_get ( ) , this ) ;
}
2009-03-03 19:31:44 -08:00
}
}
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
// Calling write() with a 0 length buffer, means that no more data will be written:
2009-07-17 12:17:14 -07:00
// If no more buffers are pending, fill output track buffer to make sure it is started
2009-03-03 19:31:44 -08:00
// by output mixer.
2009-07-17 12:17:14 -07:00
if ( frames = = 0 & & mBufferQueue . size ( ) = = 0 ) {
if ( mCblk - > user < mCblk - > frameCount ) {
frames = mCblk - > frameCount - mCblk - > user ;
pInBuffer = new Buffer ;
2010-05-14 05:45:46 -07:00
pInBuffer - > mBuffer = new int16_t [ frames * channelCount ] ;
2009-07-17 12:17:14 -07:00
pInBuffer - > frameCount = frames ;
pInBuffer - > i16 = pInBuffer - > mBuffer ;
2010-05-14 05:45:46 -07:00
memset ( pInBuffer - > raw , 0 , frames * channelCount * sizeof ( int16_t ) ) ;
2009-07-17 12:17:14 -07:00
mBufferQueue . add ( pInBuffer ) ;
2009-10-05 20:29:18 -07:00
} else if ( mActive ) {
2009-07-17 12:17:14 -07:00
stop ( ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
return outputBufferFull ;
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : PlaybackThread : : OutputTrack : : obtainBuffer ( AudioBufferProvider : : Buffer * buffer , uint32_t waitTimeMs )
2009-03-03 19:31:44 -08:00
{
int active ;
status_t result ;
audio_track_cblk_t * cblk = mCblk ;
uint32_t framesReq = buffer - > frameCount ;
2009-07-17 12:17:14 -07:00
// LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
2009-03-03 19:31:44 -08:00
buffer - > frameCount = 0 ;
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
uint32_t framesAvail = cblk - > framesAvailable ( ) ;
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
if ( framesAvail = = 0 ) {
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( cblk - > lock ) ;
goto start_loop_here ;
while ( framesAvail = = 0 ) {
active = mActive ;
if ( UNLIKELY ( ! active ) ) {
LOGV ( " Not active and NO_MORE_BUFFERS " ) ;
return AudioTrack : : NO_MORE_BUFFERS ;
}
result = cblk - > cv . waitRelative ( cblk - > lock , milliseconds ( waitTimeMs ) ) ;
if ( result ! = NO_ERROR ) {
return AudioTrack : : NO_MORE_BUFFERS ;
}
// read the server count again
start_loop_here :
framesAvail = cblk - > framesAvailable_l ( ) ;
}
2009-03-03 19:31:44 -08:00
}
2009-07-17 12:17:14 -07:00
// if (framesAvail < framesReq) {
// return AudioTrack::NO_MORE_BUFFERS;
// }
2009-03-03 19:31:44 -08:00
if ( framesReq > framesAvail ) {
framesReq = framesAvail ;
}
uint32_t u = cblk - > user ;
uint32_t bufferEnd = cblk - > userBase + cblk - > frameCount ;
if ( u + framesReq > bufferEnd ) {
framesReq = bufferEnd - u ;
}
buffer - > frameCount = framesReq ;
buffer - > raw = ( void * ) cblk - > buffer ( u ) ;
return NO_ERROR ;
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : PlaybackThread : : OutputTrack : : clearBufferQueue ( )
2009-03-03 19:31:44 -08:00
{
size_t size = mBufferQueue . size ( ) ;
Buffer * pBuffer ;
2009-07-17 12:17:14 -07:00
2009-03-03 19:31:44 -08:00
for ( size_t i = 0 ; i < size ; i + + ) {
pBuffer = mBufferQueue . itemAt ( i ) ;
delete [ ] pBuffer - > mBuffer ;
delete pBuffer ;
}
mBufferQueue . clear ( ) ;
}
// ----------------------------------------------------------------------------
AudioFlinger : : Client : : Client ( const sp < AudioFlinger > & audioFlinger , pid_t pid )
: RefBase ( ) ,
mAudioFlinger ( audioFlinger ) ,
2010-01-25 19:00:00 -08:00
mMemoryDealer ( new MemoryDealer ( 1024 * 1024 , " AudioFlinger::Client " ) ) ,
2009-03-03 19:31:44 -08:00
mPid ( pid )
{
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
2009-09-17 05:12:56 -07:00
// Client destructor must be called with AudioFlinger::mLock held
2009-03-03 19:31:44 -08:00
AudioFlinger : : Client : : ~ Client ( )
{
2009-09-17 05:12:56 -07:00
mAudioFlinger - > removeClient_l ( mPid ) ;
2009-03-03 19:31:44 -08:00
}
const sp < MemoryDealer > & AudioFlinger : : Client : : heap ( ) const
{
return mMemoryDealer ;
}
// ----------------------------------------------------------------------------
2010-05-12 02:05:53 -07:00
AudioFlinger : : NotificationClient : : NotificationClient ( const sp < AudioFlinger > & audioFlinger ,
const sp < IAudioFlingerClient > & client ,
pid_t pid )
: mAudioFlinger ( audioFlinger ) , mPid ( pid ) , mClient ( client )
{
}
AudioFlinger : : NotificationClient : : ~ NotificationClient ( )
{
mClient . clear ( ) ;
}
void AudioFlinger : : NotificationClient : : binderDied ( const wp < IBinder > & who )
{
sp < NotificationClient > keep ( this ) ;
{
mAudioFlinger - > removeNotificationClient ( mPid ) ;
}
}
// ----------------------------------------------------------------------------
2009-07-17 12:17:14 -07:00
AudioFlinger : : TrackHandle : : TrackHandle ( const sp < AudioFlinger : : PlaybackThread : : Track > & track )
2008-10-21 07:00:00 -07:00
: BnAudioTrack ( ) ,
mTrack ( track )
{
}
AudioFlinger : : TrackHandle : : ~ TrackHandle ( ) {
// just stop the track on deletion, associated resources
// will be freed from the main thread once all pending buffers have
// been played. Unless it's not in the active track list, in which
// case we free everything now...
mTrack - > destroy ( ) ;
}
status_t AudioFlinger : : TrackHandle : : start ( ) {
return mTrack - > start ( ) ;
}
void AudioFlinger : : TrackHandle : : stop ( ) {
mTrack - > stop ( ) ;
}
void AudioFlinger : : TrackHandle : : flush ( ) {
mTrack - > flush ( ) ;
}
void AudioFlinger : : TrackHandle : : mute ( bool e ) {
mTrack - > mute ( e ) ;
}
void AudioFlinger : : TrackHandle : : pause ( ) {
mTrack - > pause ( ) ;
}
void AudioFlinger : : TrackHandle : : setVolume ( float left , float right ) {
mTrack - > setVolume ( left , right ) ;
}
sp < IMemory > AudioFlinger : : TrackHandle : : getCblk ( ) const {
return mTrack - > getCblk ( ) ;
}
2010-06-01 23:49:17 -07:00
status_t AudioFlinger : : TrackHandle : : attachAuxEffect ( int EffectId )
{
return mTrack - > attachAuxEffect ( EffectId ) ;
}
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : TrackHandle : : onTransact (
uint32_t code , const Parcel & data , Parcel * reply , uint32_t flags )
{
return BnAudioTrack : : onTransact ( code , data , reply , flags ) ;
}
// ----------------------------------------------------------------------------
sp < IAudioRecord > AudioFlinger : : openRecord (
pid_t pid ,
2009-07-28 08:44:33 -07:00
int input ,
2008-10-21 07:00:00 -07:00
uint32_t sampleRate ,
2011-05-24 15:53:33 -07:00
uint32_t format ,
uint32_t channelMask ,
2008-12-17 18:05:43 -08:00
int frameCount ,
uint32_t flags ,
2010-06-01 23:49:17 -07:00
int * sessionId ,
2008-12-17 18:05:43 -08:00
status_t * status )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
sp < RecordThread : : RecordTrack > recordTrack ;
2008-10-21 07:00:00 -07:00
sp < RecordHandle > recordHandle ;
sp < Client > client ;
wp < Client > wclient ;
2008-12-17 18:05:43 -08:00
status_t lStatus ;
2009-07-17 12:17:14 -07:00
RecordThread * thread ;
size_t inFrameCount ;
2010-06-01 23:49:17 -07:00
int lSessionId ;
2008-10-21 07:00:00 -07:00
// check calling permissions
if ( ! recordingAllowed ( ) ) {
2008-12-17 18:05:43 -08:00
lStatus = PERMISSION_DENIED ;
2008-10-21 07:00:00 -07:00
goto Exit ;
}
// add client to list
2009-03-09 11:52:12 -07:00
{ // scope for mLock
2008-10-21 07:00:00 -07:00
Mutex : : Autolock _l ( mLock ) ;
2009-07-17 12:17:14 -07:00
thread = checkRecordThread_l ( input ) ;
if ( thread = = NULL ) {
lStatus = BAD_VALUE ;
goto Exit ;
}
2008-10-21 07:00:00 -07:00
wclient = mClients . valueFor ( pid ) ;
if ( wclient ! = NULL ) {
client = wclient . promote ( ) ;
} else {
client = new Client ( this , pid ) ;
mClients . add ( pid , client ) ;
}
2008-12-17 18:05:43 -08:00
2010-06-01 23:49:17 -07:00
// If no audio session id is provided, create one here
2011-04-19 22:30:36 -07:00
if ( sessionId ! = NULL & & * sessionId ! = AUDIO_SESSION_OUTPUT_MIX ) {
2010-06-01 23:49:17 -07:00
lSessionId = * sessionId ;
} else {
2011-06-17 21:29:58 -07:00
lSessionId = nextUniqueId ( ) ;
2010-06-01 23:49:17 -07:00
if ( sessionId ! = NULL ) {
* sessionId = lSessionId ;
}
}
2009-03-09 11:52:12 -07:00
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
2011-06-17 21:29:58 -07:00
recordTrack = thread - > createRecordTrack_l ( client ,
sampleRate ,
format ,
channelMask ,
frameCount ,
flags ,
lSessionId ,
& lStatus ) ;
}
if ( lStatus ! = NO_ERROR ) {
2009-09-17 05:12:56 -07:00
// remove local strong reference to Client before deleting the RecordTrack so that the Client
// destructor is called by the TrackBase destructor with mLock held
client . clear ( ) ;
2009-03-03 19:31:44 -08:00
recordTrack . clear ( ) ;
goto Exit ;
}
2008-10-21 07:00:00 -07:00
// return to handle to client
recordHandle = new RecordHandle ( recordTrack ) ;
2008-12-17 18:05:43 -08:00
lStatus = NO_ERROR ;
2008-10-21 07:00:00 -07:00
Exit :
2008-12-17 18:05:43 -08:00
if ( status ) {
* status = lStatus ;
}
2008-10-21 07:00:00 -07:00
return recordHandle ;
}
// ----------------------------------------------------------------------------
2009-07-17 12:17:14 -07:00
AudioFlinger : : RecordHandle : : RecordHandle ( const sp < AudioFlinger : : RecordThread : : RecordTrack > & recordTrack )
2008-10-21 07:00:00 -07:00
: BnAudioRecord ( ) ,
mRecordTrack ( recordTrack )
{
}
2008-12-17 18:05:43 -08:00
AudioFlinger : : RecordHandle : : ~ RecordHandle ( ) {
stop ( ) ;
}
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : RecordHandle : : start ( ) {
LOGV ( " RecordHandle::start() " ) ;
return mRecordTrack - > start ( ) ;
}
void AudioFlinger : : RecordHandle : : stop ( ) {
LOGV ( " RecordHandle::stop() " ) ;
mRecordTrack - > stop ( ) ;
}
sp < IMemory > AudioFlinger : : RecordHandle : : getCblk ( ) const {
return mRecordTrack - > getCblk ( ) ;
}
status_t AudioFlinger : : RecordHandle : : onTransact (
uint32_t code , const Parcel & data , Parcel * reply , uint32_t flags )
{
return BnAudioRecord : : onTransact ( code , data , reply , flags ) ;
}
// ----------------------------------------------------------------------------
2011-06-17 21:29:58 -07:00
AudioFlinger : : RecordThread : : RecordThread ( const sp < AudioFlinger > & audioFlinger ,
AudioStreamIn * input ,
uint32_t sampleRate ,
uint32_t channels ,
int id ,
uint32_t device ) :
ThreadBase ( audioFlinger , id , device ) ,
mInput ( input ) , mTrack ( NULL ) , mResampler ( 0 ) , mRsmpOutBuffer ( 0 ) , mRsmpInBuffer ( 0 )
2008-10-21 07:00:00 -07:00
{
2011-06-17 21:29:58 -07:00
mType = ThreadBase : : RECORD ;
2011-07-22 09:04:31 -07:00
snprintf ( mName , kNameLength , " AudioIn_%d " , id ) ;
2011-04-19 22:30:36 -07:00
mReqChannelCount = popcount ( channels ) ;
2009-07-17 12:17:14 -07:00
mReqSampleRate = sampleRate ;
readInputParameters ( ) ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
AudioFlinger : : RecordThread : : ~ RecordThread ( )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
delete [ ] mRsmpInBuffer ;
if ( mResampler ! = 0 ) {
delete mResampler ;
delete [ ] mRsmpOutBuffer ;
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : RecordThread : : onFirstRef ( )
{
2011-07-22 09:04:31 -07:00
run ( mName , PRIORITY_URGENT_AUDIO ) ;
2009-07-17 12:17:14 -07:00
}
2009-11-19 09:00:56 -08:00
2011-08-07 16:32:26 -07:00
status_t AudioFlinger : : RecordThread : : readyToRun ( )
{
status_t status = initCheck ( ) ;
LOGW_IF ( status ! = NO_ERROR , " RecordThread %p could not initialize " , this ) ;
return status ;
}
2009-07-17 12:17:14 -07:00
bool AudioFlinger : : RecordThread : : threadLoop ( )
2008-10-21 07:00:00 -07:00
{
2008-12-17 18:05:43 -08:00
AudioBufferProvider : : Buffer buffer ;
2009-07-17 12:17:14 -07:00
sp < RecordTrack > activeTrack ;
2011-06-17 21:29:58 -07:00
Vector < sp < EffectChain > > effectChains ;
2008-10-21 07:00:00 -07:00
2010-09-30 16:12:31 -07:00
nsecs_t lastWarning = 0 ;
2011-07-22 09:04:31 -07:00
acquireWakeLock ( ) ;
2008-10-21 07:00:00 -07:00
// start recording
while ( ! exitPending ( ) ) {
2009-07-17 12:17:14 -07:00
processConfigEvents ( ) ;
{ // scope for mLock
Mutex : : Autolock _l ( mLock ) ;
checkForNewParameters_l ( ) ;
if ( mActiveTrack = = 0 & & mConfigEvents . isEmpty ( ) ) {
if ( ! mStandby ) {
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mStandby = true ;
2008-12-17 18:05:43 -08:00
}
2009-07-17 12:17:14 -07:00
if ( exitPending ( ) ) break ;
2011-07-22 09:04:31 -07:00
releaseWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " RecordThread: loop stopping " ) ;
// go to sleep
2008-10-21 07:00:00 -07:00
mWaitWorkCV . wait ( mLock ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " RecordThread: loop starting " ) ;
2011-07-22 09:04:31 -07:00
acquireWakeLock_l ( ) ;
2009-07-17 12:17:14 -07:00
continue ;
}
if ( mActiveTrack ! = 0 ) {
if ( mActiveTrack - > mState = = TrackBase : : PAUSING ) {
2009-12-05 05:20:01 -08:00
if ( ! mStandby ) {
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
2009-12-05 05:20:01 -08:00
mStandby = true ;
}
2009-07-17 12:17:14 -07:00
mActiveTrack . clear ( ) ;
mStartStopCond . broadcast ( ) ;
} else if ( mActiveTrack - > mState = = TrackBase : : RESUMING ) {
if ( mReqChannelCount ! = mActiveTrack - > channelCount ( ) ) {
mActiveTrack . clear ( ) ;
2009-12-05 05:20:01 -08:00
mStartStopCond . broadcast ( ) ;
} else if ( mBytesRead ! = 0 ) {
// record start succeeds only if first read from audio input
// succeeds
if ( mBytesRead > 0 ) {
mActiveTrack - > mState = TrackBase : : ACTIVE ;
} else {
mActiveTrack . clear ( ) ;
}
mStartStopCond . broadcast ( ) ;
2008-12-17 18:05:43 -08:00
}
2009-12-05 05:20:01 -08:00
mStandby = false ;
2008-12-17 18:05:43 -08:00
}
2008-10-21 07:00:00 -07:00
}
2011-06-17 21:29:58 -07:00
lockEffectChains_l ( effectChains ) ;
2009-07-17 12:17:14 -07:00
}
if ( mActiveTrack ! = 0 ) {
2009-12-05 05:20:01 -08:00
if ( mActiveTrack - > mState ! = TrackBase : : ACTIVE & &
mActiveTrack - > mState ! = TrackBase : : RESUMING ) {
2011-06-17 21:29:58 -07:00
unlockEffectChains ( effectChains ) ;
usleep ( kRecordThreadSleepUs ) ;
2009-11-19 09:00:56 -08:00
continue ;
}
2011-06-17 21:29:58 -07:00
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
effectChains [ i ] - > process_l ( ) ;
}
2009-07-17 12:17:14 -07:00
buffer . frameCount = mFrameCount ;
if ( LIKELY ( mActiveTrack - > getNextBuffer ( & buffer ) = = NO_ERROR ) ) {
size_t framesOut = buffer . frameCount ;
if ( mResampler = = 0 ) {
// no resampling
while ( framesOut ) {
size_t framesIn = mFrameCount - mRsmpInIndex ;
if ( framesIn ) {
int8_t * src = ( int8_t * ) mRsmpInBuffer + mRsmpInIndex * mFrameSize ;
int8_t * dst = buffer . i8 + ( buffer . frameCount - framesOut ) * mActiveTrack - > mCblk - > frameSize ;
if ( framesIn > framesOut )
framesIn = framesOut ;
mRsmpInIndex + = framesIn ;
framesOut - = framesIn ;
2010-05-14 05:45:46 -07:00
if ( ( int ) mChannelCount = = mReqChannelCount | |
2011-04-19 22:30:36 -07:00
mFormat ! = AUDIO_FORMAT_PCM_16_BIT ) {
2009-07-17 12:17:14 -07:00
memcpy ( dst , src , framesIn * mFrameSize ) ;
} else {
int16_t * src16 = ( int16_t * ) src ;
int16_t * dst16 = ( int16_t * ) dst ;
if ( mChannelCount = = 1 ) {
while ( framesIn - - ) {
* dst16 + + = * src16 ;
* dst16 + + = * src16 + + ;
}
} else {
while ( framesIn - - ) {
* dst16 + + = ( int16_t ) ( ( ( int32_t ) * src16 + ( int32_t ) * ( src16 + 1 ) ) > > 1 ) ;
src16 + = 2 ;
}
}
}
}
if ( framesOut & & mFrameCount = = mRsmpInIndex ) {
if ( framesOut = = mFrameCount & &
2011-04-19 22:30:36 -07:00
( ( int ) mChannelCount = = mReqChannelCount | | mFormat ! = AUDIO_FORMAT_PCM_16_BIT ) ) {
2011-04-18 16:57:27 -07:00
mBytesRead = mInput - > stream - > read ( mInput - > stream , buffer . raw , mInputBytes ) ;
2009-07-17 12:17:14 -07:00
framesOut = 0 ;
} else {
2011-04-18 16:57:27 -07:00
mBytesRead = mInput - > stream - > read ( mInput - > stream , mRsmpInBuffer , mInputBytes ) ;
2009-07-17 12:17:14 -07:00
mRsmpInIndex = 0 ;
}
2009-12-05 05:20:01 -08:00
if ( mBytesRead < 0 ) {
2009-07-17 12:17:14 -07:00
LOGE ( " Error reading audio input " ) ;
2009-12-05 05:20:01 -08:00
if ( mActiveTrack - > mState = = TrackBase : : ACTIVE ) {
2010-03-02 18:38:06 -08:00
// Force input into standby so that it tries to
// recover at next read attempt
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
2011-06-17 21:29:58 -07:00
usleep ( kRecordThreadSleepUs ) ;
2009-12-05 05:20:01 -08:00
}
2009-07-17 12:17:14 -07:00
mRsmpInIndex = mFrameCount ;
framesOut = 0 ;
buffer . frameCount = 0 ;
}
}
}
} else {
// resampling
memset ( mRsmpOutBuffer , 0 , framesOut * 2 * sizeof ( int32_t ) ) ;
// alter output frame count as if we were expecting stereo samples
if ( mChannelCount = = 1 & & mReqChannelCount = = 1 ) {
framesOut > > = 1 ;
}
mResampler - > resample ( mRsmpOutBuffer , framesOut , this ) ;
// ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
// are 32 bit aligned which should be always true.
if ( mChannelCount = = 2 & & mReqChannelCount = = 1 ) {
AudioMixer : : ditherAndClamp ( mRsmpOutBuffer , mRsmpOutBuffer , framesOut ) ;
// the resampler always outputs stereo samples: do post stereo to mono conversion
int16_t * src = ( int16_t * ) mRsmpOutBuffer ;
int16_t * dst = buffer . i16 ;
while ( framesOut - - ) {
* dst + + = ( int16_t ) ( ( ( int32_t ) * src + ( int32_t ) * ( src + 1 ) ) > > 1 ) ;
src + = 2 ;
}
} else {
AudioMixer : : ditherAndClamp ( ( int32_t * ) buffer . raw , mRsmpOutBuffer , framesOut ) ;
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
mActiveTrack - > releaseBuffer ( & buffer ) ;
mActiveTrack - > overflow ( ) ;
2008-10-21 07:00:00 -07:00
}
// client isn't retrieving buffers fast enough
else {
2010-09-30 16:12:31 -07:00
if ( ! mActiveTrack - > setOverflow ( ) ) {
nsecs_t now = systemTime ( ) ;
if ( ( now - lastWarning ) > kWarningThrottle ) {
LOGW ( " RecordThread: buffer overflow " ) ;
lastWarning = now ;
}
}
2008-12-17 18:05:43 -08:00
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
2011-06-17 21:29:58 -07:00
usleep ( kRecordThreadSleepUs ) ;
2008-10-21 07:00:00 -07:00
}
}
2011-07-26 20:54:46 -07:00
// enable changes in effect chain
unlockEffectChains ( effectChains ) ;
2011-06-17 21:29:58 -07:00
effectChains . clear ( ) ;
2008-12-17 18:05:43 -08:00
}
2008-10-21 07:00:00 -07:00
2009-07-17 12:17:14 -07:00
if ( ! mStandby ) {
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
mActiveTrack . clear ( ) ;
2009-11-19 09:00:56 -08:00
mStartStopCond . broadcast ( ) ;
2011-07-22 09:04:31 -07:00
releaseWakeLock ( ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " RecordThread %p exiting " , this ) ;
2008-12-17 18:05:43 -08:00
return false ;
2008-10-21 07:00:00 -07:00
}
2011-06-17 21:29:58 -07:00
sp < AudioFlinger : : RecordThread : : RecordTrack > AudioFlinger : : RecordThread : : createRecordTrack_l (
const sp < AudioFlinger : : Client > & client ,
uint32_t sampleRate ,
int format ,
int channelMask ,
int frameCount ,
uint32_t flags ,
int sessionId ,
status_t * status )
{
sp < RecordTrack > track ;
status_t lStatus ;
lStatus = initCheck ( ) ;
if ( lStatus ! = NO_ERROR ) {
LOGE ( " Audio driver not initialized. " ) ;
goto Exit ;
}
{ // scope for mLock
Mutex : : Autolock _l ( mLock ) ;
track = new RecordTrack ( this , client , sampleRate ,
format , channelMask , frameCount , flags , sessionId ) ;
if ( track - > getCblk ( ) = = NULL ) {
lStatus = NO_MEMORY ;
goto Exit ;
}
mTrack = track . get ( ) ;
2011-08-01 09:52:20 -07:00
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
bool suspend = audio_is_bluetooth_sco_device (
2011-08-29 12:42:48 -07:00
( audio_devices_t ) ( mDevice & AUDIO_DEVICE_IN_ALL ) ) & & mAudioFlinger - > btNrecIsOff ( ) ;
2011-08-01 09:52:20 -07:00
setEffectSuspended_l ( FX_IID_AEC , suspend , sessionId ) ;
setEffectSuspended_l ( FX_IID_NS , suspend , sessionId ) ;
2011-06-17 21:29:58 -07:00
}
lStatus = NO_ERROR ;
Exit :
if ( status ) {
* status = lStatus ;
}
return track ;
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : RecordThread : : start ( RecordThread : : RecordTrack * recordTrack )
2008-10-21 07:00:00 -07:00
{
2009-07-17 12:17:14 -07:00
LOGV ( " RecordThread::start " ) ;
2009-11-19 09:00:56 -08:00
sp < ThreadBase > strongMe = this ;
status_t status = NO_ERROR ;
{
AutoMutex lock ( & mLock ) ;
if ( mActiveTrack ! = 0 ) {
if ( recordTrack ! = mActiveTrack . get ( ) ) {
status = - EBUSY ;
} else if ( mActiveTrack - > mState = = TrackBase : : PAUSING ) {
2009-12-05 05:20:01 -08:00
mActiveTrack - > mState = TrackBase : : ACTIVE ;
2009-11-19 09:00:56 -08:00
}
return status ;
}
2009-07-17 12:17:14 -07:00
2009-11-19 09:00:56 -08:00
recordTrack - > mState = TrackBase : : IDLE ;
mActiveTrack = recordTrack ;
mLock . unlock ( ) ;
status_t status = AudioSystem : : startInput ( mId ) ;
mLock . lock ( ) ;
if ( status ! = NO_ERROR ) {
mActiveTrack . clear ( ) ;
return status ;
}
2009-12-05 05:20:01 -08:00
mRsmpInIndex = mFrameCount ;
mBytesRead = 0 ;
2011-02-28 16:52:51 -08:00
if ( mResampler ! = NULL ) {
mResampler - > reset ( ) ;
}
mActiveTrack - > mState = TrackBase : : RESUMING ;
2009-11-19 09:00:56 -08:00
// signal thread to start
LOGV ( " Signal record thread " ) ;
mWaitWorkCV . signal ( ) ;
// do not wait for mStartStopCond if exiting
if ( mExiting ) {
mActiveTrack . clear ( ) ;
status = INVALID_OPERATION ;
goto startError ;
}
mStartStopCond . wait ( mLock ) ;
if ( mActiveTrack = = 0 ) {
LOGV ( " Record failed to start " ) ;
status = BAD_VALUE ;
goto startError ;
}
2009-07-17 12:17:14 -07:00
LOGV ( " Record started OK " ) ;
2009-11-19 09:00:56 -08:00
return status ;
2008-10-21 07:00:00 -07:00
}
2009-11-19 09:00:56 -08:00
startError :
AudioSystem : : stopInput ( mId ) ;
return status ;
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
void AudioFlinger : : RecordThread : : stop ( RecordThread : : RecordTrack * recordTrack ) {
LOGV ( " RecordThread::stop " ) ;
2009-11-19 09:00:56 -08:00
sp < ThreadBase > strongMe = this ;
{
AutoMutex lock ( & mLock ) ;
if ( mActiveTrack ! = 0 & & recordTrack = = mActiveTrack . get ( ) ) {
mActiveTrack - > mState = TrackBase : : PAUSING ;
// do not wait for mStartStopCond if exiting
if ( mExiting ) {
return ;
}
mStartStopCond . wait ( mLock ) ;
// if we have been restarted, recordTrack == mActiveTrack.get() here
if ( mActiveTrack = = 0 | | recordTrack ! = mActiveTrack . get ( ) ) {
mLock . unlock ( ) ;
AudioSystem : : stopInput ( mId ) ;
mLock . lock ( ) ;
2009-12-05 05:20:01 -08:00
LOGV ( " Record stopped OK " ) ;
2009-11-19 09:00:56 -08:00
}
}
2008-12-17 18:05:43 -08:00
}
2008-10-21 07:00:00 -07:00
}
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : RecordThread : : dump ( int fd , const Vector < String16 > & args )
2009-03-03 19:31:44 -08:00
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
pid_t pid = 0 ;
2009-11-07 00:01:32 -08:00
snprintf ( buffer , SIZE , " \n Input thread %p internals \n " , this ) ;
result . append ( buffer ) ;
if ( mActiveTrack ! = 0 ) {
result . append ( " Active Track: \n " ) ;
2011-05-24 15:53:33 -07:00
result . append ( " Clien Fmt Chn mask Session Buf S SRate Serv User \n " ) ;
2009-11-07 00:01:32 -08:00
mActiveTrack - > dump ( buffer , SIZE ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " In index: %d \n " , mRsmpInIndex ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " In size: %d \n " , mInputBytes ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Resampling: %d \n " , ( mResampler ! = 0 ) ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Out channel count: %d \n " , mReqChannelCount ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " Out sample rate: %d \n " , mReqSampleRate ) ;
2009-03-03 19:31:44 -08:00
result . append ( buffer ) ;
2009-11-07 00:01:32 -08:00
2009-03-03 19:31:44 -08:00
} else {
result . append ( " No record client \n " ) ;
}
write ( fd , result . string ( ) , result . size ( ) ) ;
2009-11-07 00:01:32 -08:00
dumpBase ( fd , args ) ;
2011-07-24 17:49:51 -07:00
dumpEffectChains ( fd , args ) ;
2009-11-07 00:01:32 -08:00
2009-03-03 19:31:44 -08:00
return NO_ERROR ;
}
2008-10-21 07:00:00 -07:00
2009-07-17 12:17:14 -07:00
status_t AudioFlinger : : RecordThread : : getNextBuffer ( AudioBufferProvider : : Buffer * buffer )
{
size_t framesReq = buffer - > frameCount ;
size_t framesReady = mFrameCount - mRsmpInIndex ;
int channelCount ;
if ( framesReady = = 0 ) {
2011-04-18 16:57:27 -07:00
mBytesRead = mInput - > stream - > read ( mInput - > stream , mRsmpInBuffer , mInputBytes ) ;
2009-12-05 05:20:01 -08:00
if ( mBytesRead < 0 ) {
2009-07-17 12:17:14 -07:00
LOGE ( " RecordThread::getNextBuffer() Error reading audio input " ) ;
2009-12-05 05:20:01 -08:00
if ( mActiveTrack - > mState = = TrackBase : : ACTIVE ) {
2010-03-02 18:38:06 -08:00
// Force input into standby so that it tries to
// recover at next read attempt
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
2011-06-17 21:29:58 -07:00
usleep ( kRecordThreadSleepUs ) ;
2009-12-05 05:20:01 -08:00
}
2009-07-17 12:17:14 -07:00
buffer - > raw = 0 ;
buffer - > frameCount = 0 ;
return NOT_ENOUGH_DATA ;
}
mRsmpInIndex = 0 ;
framesReady = mFrameCount ;
}
if ( framesReq > framesReady ) {
framesReq = framesReady ;
}
if ( mChannelCount = = 1 & & mReqChannelCount = = 2 ) {
channelCount = 1 ;
} else {
channelCount = 2 ;
}
buffer - > raw = mRsmpInBuffer + mRsmpInIndex * channelCount ;
buffer - > frameCount = framesReq ;
return NO_ERROR ;
}
void AudioFlinger : : RecordThread : : releaseBuffer ( AudioBufferProvider : : Buffer * buffer )
{
mRsmpInIndex + = buffer - > frameCount ;
buffer - > frameCount = 0 ;
}
bool AudioFlinger : : RecordThread : : checkForNewParameters_l ( )
{
bool reconfig = false ;
2009-08-04 09:45:33 -07:00
while ( ! mNewParameters . isEmpty ( ) ) {
2009-07-17 12:17:14 -07:00
status_t status = NO_ERROR ;
2009-08-04 09:45:33 -07:00
String8 keyValuePair = mNewParameters [ 0 ] ;
AudioParameter param = AudioParameter ( keyValuePair ) ;
2009-07-17 12:17:14 -07:00
int value ;
int reqFormat = mFormat ;
int reqSamplingRate = mReqSampleRate ;
int reqChannelCount = mReqChannelCount ;
2009-08-04 09:45:33 -07:00
2009-07-17 12:17:14 -07:00
if ( param . getInt ( String8 ( AudioParameter : : keySamplingRate ) , value ) = = NO_ERROR ) {
reqSamplingRate = value ;
reconfig = true ;
}
if ( param . getInt ( String8 ( AudioParameter : : keyFormat ) , value ) = = NO_ERROR ) {
reqFormat = value ;
reconfig = true ;
}
if ( param . getInt ( String8 ( AudioParameter : : keyChannels ) , value ) = = NO_ERROR ) {
2011-04-19 22:30:36 -07:00
reqChannelCount = popcount ( value ) ;
2009-07-17 12:17:14 -07:00
reconfig = true ;
}
if ( param . getInt ( String8 ( AudioParameter : : keyFrameCount ) , value ) = = NO_ERROR ) {
// do not accept frame count changes if tracks are open as the track buffer
// size depends on frame count and correct behavior would not be garantied
// if frame count is changed after track creation
if ( mActiveTrack ! = 0 ) {
status = INVALID_OPERATION ;
} else {
reconfig = true ;
}
}
2011-06-17 21:29:58 -07:00
if ( param . getInt ( String8 ( AudioParameter : : keyRouting ) , value ) = = NO_ERROR ) {
// forward device change to effects that have requested to be
// aware of attached audio device.
for ( size_t i = 0 ; i < mEffectChains . size ( ) ; i + + ) {
mEffectChains [ i ] - > setDevice_l ( value ) ;
}
// store input device and output device but do not forward output device to audio HAL.
// Note that status is ignored by the caller for output device
// (see AudioFlinger::setParameters()
if ( value & AUDIO_DEVICE_OUT_ALL ) {
mDevice & = ( uint32_t ) ~ ( value & AUDIO_DEVICE_OUT_ALL ) ;
status = BAD_VALUE ;
} else {
mDevice & = ( uint32_t ) ~ ( value & AUDIO_DEVICE_IN_ALL ) ;
2011-08-01 09:52:20 -07:00
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
if ( mTrack ! = NULL ) {
bool suspend = audio_is_bluetooth_sco_device (
2011-08-29 12:42:48 -07:00
( audio_devices_t ) value ) & & mAudioFlinger - > btNrecIsOff ( ) ;
2011-08-01 09:52:20 -07:00
setEffectSuspended_l ( FX_IID_AEC , suspend , mTrack - > sessionId ( ) ) ;
setEffectSuspended_l ( FX_IID_NS , suspend , mTrack - > sessionId ( ) ) ;
}
2011-06-17 21:29:58 -07:00
}
mDevice | = ( uint32_t ) value ;
}
2009-07-17 12:17:14 -07:00
if ( status = = NO_ERROR ) {
2011-04-18 16:57:27 -07:00
status = mInput - > stream - > common . set_parameters ( & mInput - > stream - > common , keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
if ( status = = INVALID_OPERATION ) {
2011-04-18 16:57:27 -07:00
mInput - > stream - > common . standby ( & mInput - > stream - > common ) ;
status = mInput - > stream - > common . set_parameters ( & mInput - > stream - > common , keyValuePair . string ( ) ) ;
2009-07-17 12:17:14 -07:00
}
if ( reconfig ) {
if ( status = = BAD_VALUE & &
2011-04-18 16:57:27 -07:00
reqFormat = = mInput - > stream - > common . get_format ( & mInput - > stream - > common ) & &
2011-04-19 22:30:36 -07:00
reqFormat = = AUDIO_FORMAT_PCM_16_BIT & &
2011-04-18 16:57:27 -07:00
( ( int ) mInput - > stream - > common . get_sample_rate ( & mInput - > stream - > common ) < = ( 2 * reqSamplingRate ) ) & &
( popcount ( mInput - > stream - > common . get_channels ( & mInput - > stream - > common ) ) < 3 ) & &
2011-04-19 22:30:36 -07:00
( reqChannelCount < 3 ) ) {
2009-07-17 12:17:14 -07:00
status = NO_ERROR ;
}
if ( status = = NO_ERROR ) {
readInputParameters ( ) ;
2009-08-04 09:45:33 -07:00
sendConfigEvent_l ( AudioSystem : : INPUT_CONFIG_CHANGED ) ;
2009-07-17 12:17:14 -07:00
}
}
}
2009-11-07 00:01:32 -08:00
mNewParameters . removeAt ( 0 ) ;
2009-07-17 12:17:14 -07:00
mParamStatus = status ;
mParamCond . signal ( ) ;
2011-09-13 11:40:21 -07:00
// wait for condition with time out in case the thread calling ThreadBase::setParameters()
// already timed out waiting for the status and will never signal the condition.
mWaitWorkCV . waitRelative ( mLock , kSetParametersTimeout ) ;
2009-07-17 12:17:14 -07:00
}
return reconfig ;
}
String8 AudioFlinger : : RecordThread : : getParameters ( const String8 & keys )
{
2011-04-19 22:30:36 -07:00
char * s ;
2011-08-07 16:32:26 -07:00
String8 out_s8 = String8 ( ) ;
Mutex : : Autolock _l ( mLock ) ;
if ( initCheck ( ) ! = NO_ERROR ) {
return out_s8 ;
}
2011-04-19 22:30:36 -07:00
2011-04-18 16:57:27 -07:00
s = mInput - > stream - > common . get_parameters ( & mInput - > stream - > common , keys . string ( ) ) ;
2011-04-19 22:30:36 -07:00
out_s8 = String8 ( s ) ;
free ( s ) ;
return out_s8 ;
2009-07-17 12:17:14 -07:00
}
2010-05-14 03:26:45 -07:00
void AudioFlinger : : RecordThread : : audioConfigChanged_l ( int event , int param ) {
2009-07-17 12:17:14 -07:00
AudioSystem : : OutputDescriptor desc ;
void * param2 = 0 ;
switch ( event ) {
case AudioSystem : : INPUT_OPENED :
case AudioSystem : : INPUT_CONFIG_CHANGED :
2011-05-24 15:53:33 -07:00
desc . channels = mChannelMask ;
2009-07-17 12:17:14 -07:00
desc . samplingRate = mSampleRate ;
desc . format = mFormat ;
desc . frameCount = mFrameCount ;
desc . latency = 0 ;
param2 = & desc ;
break ;
case AudioSystem : : INPUT_CLOSED :
default :
break ;
}
2009-11-19 09:00:56 -08:00
mAudioFlinger - > audioConfigChanged_l ( event , mId , param2 ) ;
2009-07-17 12:17:14 -07:00
}
void AudioFlinger : : RecordThread : : readInputParameters ( )
{
if ( mRsmpInBuffer ) delete mRsmpInBuffer ;
if ( mRsmpOutBuffer ) delete mRsmpOutBuffer ;
if ( mResampler ) delete mResampler ;
mResampler = 0 ;
2011-04-18 16:57:27 -07:00
mSampleRate = mInput - > stream - > common . get_sample_rate ( & mInput - > stream - > common ) ;
2011-05-24 15:53:33 -07:00
mChannelMask = mInput - > stream - > common . get_channels ( & mInput - > stream - > common ) ;
mChannelCount = ( uint16_t ) popcount ( mChannelMask ) ;
2011-04-18 16:57:27 -07:00
mFormat = mInput - > stream - > common . get_format ( & mInput - > stream - > common ) ;
mFrameSize = ( uint16_t ) audio_stream_frame_size ( & mInput - > stream - > common ) ;
mInputBytes = mInput - > stream - > common . get_buffer_size ( & mInput - > stream - > common ) ;
2009-07-17 12:17:14 -07:00
mFrameCount = mInputBytes / mFrameSize ;
mRsmpInBuffer = new int16_t [ mFrameCount * mChannelCount ] ;
if ( mSampleRate ! = mReqSampleRate & & mChannelCount < 3 & & mReqChannelCount < 3 )
{
int channelCount ;
// optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid
// stereo to mono post process as the resampler always outputs stereo.
if ( mChannelCount = = 1 & & mReqChannelCount = = 2 ) {
channelCount = 1 ;
} else {
channelCount = 2 ;
}
mResampler = AudioResampler : : create ( 16 , channelCount , mReqSampleRate ) ;
mResampler - > setSampleRate ( mSampleRate ) ;
mResampler - > setVolume ( AudioMixer : : UNITY_GAIN , AudioMixer : : UNITY_GAIN ) ;
mRsmpOutBuffer = new int32_t [ mFrameCount * 2 ] ;
// optmization: if mono to mono, alter input frame count as if we were inputing stereo samples
if ( mChannelCount = = 1 & & mReqChannelCount = = 1 ) {
mFrameCount > > = 1 ;
}
}
mRsmpInIndex = mFrameCount ;
}
2010-02-26 02:47:27 -08:00
unsigned int AudioFlinger : : RecordThread : : getInputFramesLost ( )
{
2011-08-07 16:32:26 -07:00
Mutex : : Autolock _l ( mLock ) ;
if ( initCheck ( ) ! = NO_ERROR ) {
return 0 ;
}
2011-04-18 16:57:27 -07:00
return mInput - > stream - > get_input_frames_lost ( mInput - > stream ) ;
2010-02-26 02:47:27 -08:00
}
2011-06-17 21:29:58 -07:00
uint32_t AudioFlinger : : RecordThread : : hasAudioSession ( int sessionId )
{
Mutex : : Autolock _l ( mLock ) ;
uint32_t result = 0 ;
if ( getEffectChain_l ( sessionId ) ! = 0 ) {
result = EFFECT_SESSION ;
}
if ( mTrack ! = NULL & & sessionId = = mTrack - > sessionId ( ) ) {
result | = TRACK_SESSION ;
}
return result ;
}
2011-08-01 09:52:20 -07:00
AudioFlinger : : RecordThread : : RecordTrack * AudioFlinger : : RecordThread : : track ( )
{
Mutex : : Autolock _l ( mLock ) ;
return mTrack ;
}
2011-08-07 16:32:26 -07:00
AudioFlinger : : AudioStreamIn * AudioFlinger : : RecordThread : : getInput ( )
{
Mutex : : Autolock _l ( mLock ) ;
return mInput ;
}
AudioFlinger : : AudioStreamIn * AudioFlinger : : RecordThread : : clearInput ( )
{
Mutex : : Autolock _l ( mLock ) ;
AudioStreamIn * input = mInput ;
mInput = NULL ;
return input ;
}
// this method must always be called either with ThreadBase mLock held or inside the thread loop
audio_stream_t * AudioFlinger : : RecordThread : : stream ( )
{
if ( mInput = = NULL ) {
return NULL ;
}
return & mInput - > stream - > common ;
}
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2009-07-28 08:44:33 -07:00
int AudioFlinger : : openOutput ( uint32_t * pDevices ,
2009-07-17 12:17:14 -07:00
uint32_t * pSamplingRate ,
uint32_t * pFormat ,
uint32_t * pChannels ,
uint32_t * pLatencyMs ,
uint32_t flags )
{
status_t status ;
PlaybackThread * thread = NULL ;
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN ;
uint32_t samplingRate = pSamplingRate ? * pSamplingRate : 0 ;
uint32_t format = pFormat ? * pFormat : 0 ;
uint32_t channels = pChannels ? * pChannels : 0 ;
uint32_t latency = pLatencyMs ? * pLatencyMs : 0 ;
2011-04-18 16:57:27 -07:00
audio_stream_out_t * outStream ;
audio_hw_device_t * outHwDev ;
2009-07-17 12:17:14 -07:00
LOGV ( " openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x " ,
pDevices ? * pDevices : 0 ,
samplingRate ,
format ,
channels ,
flags ) ;
if ( pDevices = = NULL | | * pDevices = = 0 ) {
2009-07-28 08:44:33 -07:00
return 0 ;
2009-07-17 12:17:14 -07:00
}
2011-04-18 16:57:27 -07:00
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
2011-04-18 16:57:27 -07:00
outHwDev = findSuitableHwDev_l ( * pDevices ) ;
if ( outHwDev = = NULL )
return 0 ;
status = outHwDev - > open_output_stream ( outHwDev , * pDevices , ( int * ) & format ,
& channels , & samplingRate , & outStream ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d " ,
2011-04-18 16:57:27 -07:00
outStream ,
2009-07-17 12:17:14 -07:00
samplingRate ,
format ,
channels ,
status ) ;
mHardwareStatus = AUDIO_HW_IDLE ;
2011-04-18 16:57:27 -07:00
if ( outStream ! = NULL ) {
AudioStreamOut * output = new AudioStreamOut ( outHwDev , outStream ) ;
2011-06-17 21:29:58 -07:00
int id = nextUniqueId ( ) ;
2011-04-18 16:57:27 -07:00
2011-04-19 22:30:36 -07:00
if ( ( flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT ) | |
( format ! = AUDIO_FORMAT_PCM_16_BIT ) | |
( channels ! = AUDIO_CHANNEL_OUT_STEREO ) ) {
2010-06-01 23:49:17 -07:00
thread = new DirectOutputThread ( this , output , id , * pDevices ) ;
LOGV ( " openOutput() created direct output: ID %d thread %p " , id , thread ) ;
2009-07-17 12:17:14 -07:00
} else {
2010-06-01 23:49:17 -07:00
thread = new MixerThread ( this , output , id , * pDevices ) ;
LOGV ( " openOutput() created mixer output: ID %d thread %p " , id , thread ) ;
2009-07-17 12:17:14 -07:00
}
2010-06-01 23:49:17 -07:00
mPlaybackThreads . add ( id , thread ) ;
2009-07-17 12:17:14 -07:00
if ( pSamplingRate ) * pSamplingRate = samplingRate ;
if ( pFormat ) * pFormat = format ;
if ( pChannels ) * pChannels = channels ;
if ( pLatencyMs ) * pLatencyMs = thread - > latency ( ) ;
2009-12-05 05:20:01 -08:00
2010-05-14 03:26:45 -07:00
// notify client processes of the new output creation
thread - > audioConfigChanged_l ( AudioSystem : : OUTPUT_OPENED ) ;
2010-06-01 23:49:17 -07:00
return id ;
2009-07-17 12:17:14 -07:00
}
2009-12-05 05:20:01 -08:00
return 0 ;
2009-07-17 12:17:14 -07:00
}
2009-07-28 08:44:33 -07:00
int AudioFlinger : : openDuplicateOutput ( int output1 , int output2 )
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
2009-07-28 08:44:33 -07:00
MixerThread * thread1 = checkMixerThread_l ( output1 ) ;
MixerThread * thread2 = checkMixerThread_l ( output2 ) ;
2009-07-17 12:17:14 -07:00
2009-07-28 08:44:33 -07:00
if ( thread1 = = NULL | | thread2 = = NULL ) {
LOGW ( " openDuplicateOutput() wrong output mixer type for output %d or %d " , output1 , output2 ) ;
return 0 ;
2009-07-17 12:17:14 -07:00
}
2011-06-17 21:29:58 -07:00
int id = nextUniqueId ( ) ;
2010-06-01 23:49:17 -07:00
DuplicatingThread * thread = new DuplicatingThread ( this , thread1 , id ) ;
2009-07-28 08:44:33 -07:00
thread - > addOutputTrack ( thread2 ) ;
2010-06-01 23:49:17 -07:00
mPlaybackThreads . add ( id , thread ) ;
2010-05-14 03:26:45 -07:00
// notify client processes of the new output creation
thread - > audioConfigChanged_l ( AudioSystem : : OUTPUT_OPENED ) ;
2010-06-01 23:49:17 -07:00
return id ;
2009-07-17 12:17:14 -07:00
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : closeOutput ( int output )
2009-07-17 12:17:14 -07:00
{
2009-08-04 08:37:05 -07:00
// keep strong reference on the playback thread so that
// it is not destroyed while exit() is executed
sp < PlaybackThread > thread ;
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
LOGV ( " closeOutput() %d " , output ) ;
2009-07-17 12:17:14 -07:00
2011-06-17 21:29:58 -07:00
if ( thread - > type ( ) = = ThreadBase : : MIXER ) {
2009-07-17 12:17:14 -07:00
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
2011-06-17 21:29:58 -07:00
if ( mPlaybackThreads . valueAt ( i ) - > type ( ) = = ThreadBase : : DUPLICATING ) {
2009-07-28 08:44:33 -07:00
DuplicatingThread * dupThread = ( DuplicatingThread * ) mPlaybackThreads . valueAt ( i ) . get ( ) ;
2009-08-04 08:37:05 -07:00
dupThread - > removeOutputTrack ( ( MixerThread * ) thread . get ( ) ) ;
2009-07-17 12:17:14 -07:00
}
}
}
2009-09-15 07:10:12 -07:00
void * param2 = 0 ;
2009-11-19 09:00:56 -08:00
audioConfigChanged_l ( AudioSystem : : OUTPUT_CLOSED , output , param2 ) ;
2009-07-28 08:44:33 -07:00
mPlaybackThreads . removeItem ( output ) ;
2009-07-17 12:17:14 -07:00
}
thread - > exit ( ) ;
2011-06-17 21:29:58 -07:00
if ( thread - > type ( ) ! = ThreadBase : : DUPLICATING ) {
2011-08-07 16:32:26 -07:00
AudioStreamOut * out = thread - > clearOutput ( ) ;
// from now on thread->mOutput is NULL
2011-04-18 16:57:27 -07:00
out - > hwDev - > close_output_stream ( out - > hwDev , out - > stream ) ;
delete out ;
2009-08-04 08:37:05 -07:00
}
2009-07-17 12:17:14 -07:00
return NO_ERROR ;
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : suspendOutput ( int output )
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
LOGV ( " suspendOutput() %d " , output ) ;
2009-07-17 12:17:14 -07:00
thread - > suspend ( ) ;
return NO_ERROR ;
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : restoreOutput ( int output )
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread = = NULL ) {
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
LOGV ( " restoreOutput() %d " , output ) ;
2009-07-17 12:17:14 -07:00
thread - > restore ( ) ;
return NO_ERROR ;
}
2009-07-28 08:44:33 -07:00
int AudioFlinger : : openInput ( uint32_t * pDevices ,
2009-07-17 12:17:14 -07:00
uint32_t * pSamplingRate ,
uint32_t * pFormat ,
uint32_t * pChannels ,
uint32_t acoustics )
{
status_t status ;
RecordThread * thread = NULL ;
uint32_t samplingRate = pSamplingRate ? * pSamplingRate : 0 ;
uint32_t format = pFormat ? * pFormat : 0 ;
uint32_t channels = pChannels ? * pChannels : 0 ;
uint32_t reqSamplingRate = samplingRate ;
uint32_t reqFormat = format ;
uint32_t reqChannels = channels ;
2011-04-18 16:57:27 -07:00
audio_stream_in_t * inStream ;
audio_hw_device_t * inHwDev ;
2009-07-17 12:17:14 -07:00
if ( pDevices = = NULL | | * pDevices = = 0 ) {
2009-07-28 08:44:33 -07:00
return 0 ;
2009-07-17 12:17:14 -07:00
}
2011-04-18 16:57:27 -07:00
2009-07-17 12:17:14 -07:00
Mutex : : Autolock _l ( mLock ) ;
2011-04-18 16:57:27 -07:00
inHwDev = findSuitableHwDev_l ( * pDevices ) ;
if ( inHwDev = = NULL )
return 0 ;
status = inHwDev - > open_input_stream ( inHwDev , * pDevices , ( int * ) & format ,
& channels , & samplingRate ,
2011-04-19 22:30:36 -07:00
( audio_in_acoustics_t ) acoustics ,
2011-04-18 16:57:27 -07:00
& inStream ) ;
2009-07-17 12:17:14 -07:00
LOGV ( " openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d " ,
2011-04-18 16:57:27 -07:00
inStream ,
2009-07-17 12:17:14 -07:00
samplingRate ,
format ,
channels ,
acoustics ,
status ) ;
// If the input could not be opened with the requested parameters and we can handle the conversion internally,
// try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
// or stereo to mono conversions on 16 bit PCM inputs.
2011-04-18 16:57:27 -07:00
if ( inStream = = NULL & & status = = BAD_VALUE & &
2011-04-19 22:30:36 -07:00
reqFormat = = format & & format = = AUDIO_FORMAT_PCM_16_BIT & &
2009-07-17 12:17:14 -07:00
( samplingRate < = 2 * reqSamplingRate ) & &
2011-04-19 22:30:36 -07:00
( popcount ( channels ) < 3 ) & & ( popcount ( reqChannels ) < 3 ) ) {
2009-07-17 12:17:14 -07:00
LOGV ( " openInput() reopening with proposed sampling rate and channels " ) ;
2011-04-18 16:57:27 -07:00
status = inHwDev - > open_input_stream ( inHwDev , * pDevices , ( int * ) & format ,
& channels , & samplingRate ,
2011-04-19 22:30:36 -07:00
( audio_in_acoustics_t ) acoustics ,
2011-04-18 16:57:27 -07:00
& inStream ) ;
2009-07-17 12:17:14 -07:00
}
2011-04-18 16:57:27 -07:00
if ( inStream ! = NULL ) {
AudioStreamIn * input = new AudioStreamIn ( inHwDev , inStream ) ;
2011-06-17 21:29:58 -07:00
int id = nextUniqueId ( ) ;
// Start record thread
// RecorThread require both input and output device indication to forward to audio
// pre processing modules
uint32_t device = ( * pDevices ) | primaryOutputDevice_l ( ) ;
thread = new RecordThread ( this ,
input ,
reqSamplingRate ,
reqChannels ,
id ,
device ) ;
2010-06-01 23:49:17 -07:00
mRecordThreads . add ( id , thread ) ;
LOGV ( " openInput() created record thread: ID %d thread %p " , id , thread ) ;
2009-07-17 12:17:14 -07:00
if ( pSamplingRate ) * pSamplingRate = reqSamplingRate ;
if ( pFormat ) * pFormat = format ;
if ( pChannels ) * pChannels = reqChannels ;
2011-04-18 16:57:27 -07:00
input - > stream - > common . standby ( & input - > stream - > common ) ;
2009-12-05 05:20:01 -08:00
2010-05-14 03:26:45 -07:00
// notify client processes of the new input creation
thread - > audioConfigChanged_l ( AudioSystem : : INPUT_OPENED ) ;
2010-06-01 23:49:17 -07:00
return id ;
2009-07-17 12:17:14 -07:00
}
2009-12-05 05:20:01 -08:00
return 0 ;
2009-07-17 12:17:14 -07:00
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : closeInput ( int input )
2009-07-17 12:17:14 -07:00
{
2009-08-04 08:37:05 -07:00
// keep strong reference on the record thread so that
// it is not destroyed while exit() is executed
sp < RecordThread > thread ;
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
thread = checkRecordThread_l ( input ) ;
if ( thread = = NULL ) {
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
LOGV ( " closeInput() %d " , input ) ;
2009-09-15 07:10:12 -07:00
void * param2 = 0 ;
2009-11-19 09:00:56 -08:00
audioConfigChanged_l ( AudioSystem : : INPUT_CLOSED , input , param2 ) ;
2009-07-28 08:44:33 -07:00
mRecordThreads . removeItem ( input ) ;
2009-07-17 12:17:14 -07:00
}
thread - > exit ( ) ;
2011-08-07 16:32:26 -07:00
AudioStreamIn * in = thread - > clearInput ( ) ;
// from now on thread->mInput is NULL
2011-04-18 16:57:27 -07:00
in - > hwDev - > close_input_stream ( in - > hwDev , in - > stream ) ;
delete in ;
2009-08-04 08:37:05 -07:00
2009-07-17 12:17:14 -07:00
return NO_ERROR ;
}
2009-07-28 08:44:33 -07:00
status_t AudioFlinger : : setStreamOutput ( uint32_t stream , int output )
2009-07-17 12:17:14 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
MixerThread * dstThread = checkMixerThread_l ( output ) ;
if ( dstThread = = NULL ) {
2009-07-28 08:44:33 -07:00
LOGW ( " setStreamOutput() bad output id %d " , output ) ;
2009-07-17 12:17:14 -07:00
return BAD_VALUE ;
}
2009-07-28 08:44:33 -07:00
LOGV ( " setStreamOutput() stream %d to output %d " , stream , output ) ;
2010-05-14 03:26:45 -07:00
audioConfigChanged_l ( AudioSystem : : STREAM_CONFIG_CHANGED , output , & stream ) ;
2009-07-17 12:17:14 -07:00
2011-08-30 10:18:54 -07:00
dstThread - > setStreamValid ( stream , true ) ;
2009-07-17 12:17:14 -07:00
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
2009-07-28 08:44:33 -07:00
PlaybackThread * thread = mPlaybackThreads . valueAt ( i ) . get ( ) ;
2009-07-17 12:17:14 -07:00
if ( thread ! = dstThread & &
2011-06-17 21:29:58 -07:00
thread - > type ( ) ! = ThreadBase : : DIRECT ) {
2009-07-17 12:17:14 -07:00
MixerThread * srcThread = ( MixerThread * ) thread ;
2011-08-30 10:18:54 -07:00
srcThread - > setStreamValid ( stream , false ) ;
2010-05-14 03:26:45 -07:00
srcThread - > invalidateTracks ( stream ) ;
2009-07-17 12:17:14 -07:00
}
2010-07-13 04:45:46 -07:00
}
2009-09-01 05:56:26 -07:00
2009-07-17 12:17:14 -07:00
return NO_ERROR ;
}
2010-06-01 23:49:17 -07:00
int AudioFlinger : : newAudioSessionId ( )
{
2011-06-17 21:29:58 -07:00
return nextUniqueId ( ) ;
2010-06-01 23:49:17 -07:00
}
2011-08-02 13:33:41 -07:00
void AudioFlinger : : acquireAudioSessionId ( int audioSession )
{
Mutex : : Autolock _l ( mLock ) ;
int caller = IPCThreadState : : self ( ) - > getCallingPid ( ) ;
LOGV ( " acquiring %d from %d " , audioSession , caller ) ;
int num = mAudioSessionRefs . size ( ) ;
for ( int i = 0 ; i < num ; i + + ) {
AudioSessionRef * ref = mAudioSessionRefs . editItemAt ( i ) ;
if ( ref - > sessionid = = audioSession & & ref - > pid = = caller ) {
ref - > cnt + + ;
LOGV ( " incremented refcount to %d " , ref - > cnt ) ;
return ;
}
}
AudioSessionRef * ref = new AudioSessionRef ( ) ;
ref - > sessionid = audioSession ;
ref - > pid = caller ;
ref - > cnt = 1 ;
mAudioSessionRefs . push ( ref ) ;
LOGV ( " added new entry for %d " , ref - > sessionid ) ;
}
void AudioFlinger : : releaseAudioSessionId ( int audioSession )
{
Mutex : : Autolock _l ( mLock ) ;
int caller = IPCThreadState : : self ( ) - > getCallingPid ( ) ;
LOGV ( " releasing %d from %d " , audioSession , caller ) ;
int num = mAudioSessionRefs . size ( ) ;
for ( int i = 0 ; i < num ; i + + ) {
AudioSessionRef * ref = mAudioSessionRefs . itemAt ( i ) ;
if ( ref - > sessionid = = audioSession & & ref - > pid = = caller ) {
ref - > cnt - - ;
LOGV ( " decremented refcount to %d " , ref - > cnt ) ;
if ( ref - > cnt = = 0 ) {
mAudioSessionRefs . removeAt ( i ) ;
delete ref ;
purgeStaleEffects_l ( ) ;
}
return ;
}
}
LOGW ( " session id %d not found for pid %d " , audioSession , caller ) ;
}
void AudioFlinger : : purgeStaleEffects_l ( ) {
LOGV ( " purging stale effects " ) ;
Vector < sp < EffectChain > > chains ;
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
sp < PlaybackThread > t = mPlaybackThreads . valueAt ( i ) ;
for ( size_t j = 0 ; j < t - > mEffectChains . size ( ) ; j + + ) {
sp < EffectChain > ec = t - > mEffectChains [ j ] ;
2011-08-12 14:14:39 -07:00
if ( ec - > sessionId ( ) > AUDIO_SESSION_OUTPUT_MIX ) {
chains . push ( ec ) ;
}
2011-08-02 13:33:41 -07:00
}
}
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
sp < RecordThread > t = mRecordThreads . valueAt ( i ) ;
for ( size_t j = 0 ; j < t - > mEffectChains . size ( ) ; j + + ) {
sp < EffectChain > ec = t - > mEffectChains [ j ] ;
chains . push ( ec ) ;
}
}
for ( size_t i = 0 ; i < chains . size ( ) ; i + + ) {
sp < EffectChain > ec = chains [ i ] ;
int sessionid = ec - > sessionId ( ) ;
sp < ThreadBase > t = ec - > mThread . promote ( ) ;
if ( t = = 0 ) {
continue ;
}
size_t numsessionrefs = mAudioSessionRefs . size ( ) ;
bool found = false ;
for ( size_t k = 0 ; k < numsessionrefs ; k + + ) {
AudioSessionRef * ref = mAudioSessionRefs . itemAt ( k ) ;
if ( ref - > sessionid = = sessionid ) {
LOGV ( " session %d still exists for %d with %d refs " ,
sessionid , ref - > pid , ref - > cnt ) ;
found = true ;
break ;
}
}
if ( ! found ) {
// remove all effects from the chain
while ( ec - > mEffects . size ( ) ) {
sp < EffectModule > effect = ec - > mEffects [ 0 ] ;
effect - > unPin ( ) ;
Mutex : : Autolock _l ( t - > mLock ) ;
t - > removeEffect_l ( effect ) ;
for ( size_t j = 0 ; j < effect - > mHandles . size ( ) ; j + + ) {
sp < EffectHandle > handle = effect - > mHandles [ j ] . promote ( ) ;
if ( handle ! = 0 ) {
handle - > mEffect . clear ( ) ;
2011-10-19 11:44:54 -07:00
if ( handle - > mHasControl & & handle - > mEnabled ) {
t - > checkSuspendOnEffectEnabled_l ( effect , false , effect - > sessionId ( ) ) ;
}
2011-08-02 13:33:41 -07:00
}
}
AudioSystem : : unregisterEffect ( effect - > id ( ) ) ;
}
}
}
return ;
}
2009-07-17 12:17:14 -07:00
// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
2009-07-28 08:44:33 -07:00
AudioFlinger : : PlaybackThread * AudioFlinger : : checkPlaybackThread_l ( int output ) const
2009-07-17 12:17:14 -07:00
{
PlaybackThread * thread = NULL ;
2009-07-28 08:44:33 -07:00
if ( mPlaybackThreads . indexOfKey ( output ) > = 0 ) {
thread = ( PlaybackThread * ) mPlaybackThreads . valueFor ( output ) . get ( ) ;
2009-07-17 12:17:14 -07:00
}
return thread ;
}
// checkMixerThread_l() must be called with AudioFlinger::mLock held
2009-07-28 08:44:33 -07:00
AudioFlinger : : MixerThread * AudioFlinger : : checkMixerThread_l ( int output ) const
2009-07-17 12:17:14 -07:00
{
PlaybackThread * thread = checkPlaybackThread_l ( output ) ;
if ( thread ! = NULL ) {
2011-06-17 21:29:58 -07:00
if ( thread - > type ( ) = = ThreadBase : : DIRECT ) {
2009-07-17 12:17:14 -07:00
thread = NULL ;
}
}
return ( MixerThread * ) thread ;
}
// checkRecordThread_l() must be called with AudioFlinger::mLock held
2009-07-28 08:44:33 -07:00
AudioFlinger : : RecordThread * AudioFlinger : : checkRecordThread_l ( int input ) const
2009-07-17 12:17:14 -07:00
{
RecordThread * thread = NULL ;
2009-07-28 08:44:33 -07:00
if ( mRecordThreads . indexOfKey ( input ) > = 0 ) {
thread = ( RecordThread * ) mRecordThreads . valueFor ( input ) . get ( ) ;
2009-07-17 12:17:14 -07:00
}
return thread ;
}
2011-06-17 21:29:58 -07:00
uint32_t AudioFlinger : : nextUniqueId ( )
{
return android_atomic_inc ( & mNextUniqueId ) ;
}
AudioFlinger : : PlaybackThread * AudioFlinger : : primaryPlaybackThread_l ( )
2010-06-01 23:49:17 -07:00
{
2011-06-17 21:29:58 -07:00
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
PlaybackThread * thread = mPlaybackThreads . valueAt ( i ) . get ( ) ;
2011-08-07 16:32:26 -07:00
AudioStreamOut * output = thread - > getOutput ( ) ;
if ( output ! = NULL & & output - > hwDev = = mPrimaryHardwareDev ) {
2011-06-17 21:29:58 -07:00
return thread ;
}
}
return NULL ;
}
uint32_t AudioFlinger : : primaryOutputDevice_l ( )
{
PlaybackThread * thread = primaryPlaybackThread_l ( ) ;
if ( thread = = NULL ) {
return 0 ;
}
return thread - > device ( ) ;
2010-06-01 23:49:17 -07:00
}
2011-06-17 21:29:58 -07:00
2010-06-01 23:49:17 -07:00
// ----------------------------------------------------------------------------
// Effect management
// ----------------------------------------------------------------------------
status_t AudioFlinger : : queryNumberEffects ( uint32_t * numEffects )
{
Mutex : : Autolock _l ( mLock ) ;
return EffectQueryNumberEffects ( numEffects ) ;
}
2010-06-23 17:38:20 -07:00
status_t AudioFlinger : : queryEffect ( uint32_t index , effect_descriptor_t * descriptor )
2010-06-01 23:49:17 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
2010-06-23 17:38:20 -07:00
return EffectQueryEffect ( index , descriptor ) ;
2010-06-01 23:49:17 -07:00
}
status_t AudioFlinger : : getEffectDescriptor ( effect_uuid_t * pUuid , effect_descriptor_t * descriptor )
{
Mutex : : Autolock _l ( mLock ) ;
return EffectGetDescriptor ( pUuid , descriptor ) ;
}
2010-07-02 08:12:41 -07:00
2010-06-01 23:49:17 -07:00
sp < IEffect > AudioFlinger : : createEffect ( pid_t pid ,
effect_descriptor_t * pDesc ,
const sp < IEffectClient > & effectClient ,
int32_t priority ,
2011-06-17 21:29:58 -07:00
int io ,
2010-06-01 23:49:17 -07:00
int sessionId ,
status_t * status ,
int * id ,
int * enabled )
{
status_t lStatus = NO_ERROR ;
sp < EffectHandle > handle ;
effect_descriptor_t desc ;
sp < Client > client ;
wp < Client > wclient ;
2011-06-17 21:29:58 -07:00
LOGV ( " createEffect pid %d, client %p, priority %d, sessionId %d, io %d " ,
pid , effectClient . get ( ) , priority , sessionId , io ) ;
2010-06-01 23:49:17 -07:00
if ( pDesc = = NULL ) {
lStatus = BAD_VALUE ;
goto Exit ;
}
2010-09-23 16:10:16 -07:00
// check audio settings permission for global effects
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_MIX & & ! settingsAllowed ( ) ) {
2010-09-23 16:10:16 -07:00
lStatus = PERMISSION_DENIED ;
goto Exit ;
}
2010-06-01 23:49:17 -07:00
2011-04-19 22:30:36 -07:00
// Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
2010-09-23 16:10:16 -07:00
// that can only be created by audio policy manager (running in same process)
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_STAGE & & getpid ( ) ! = pid ) {
2010-09-23 16:10:16 -07:00
lStatus = PERMISSION_DENIED ;
goto Exit ;
}
2010-09-22 14:17:38 -07:00
2011-06-17 21:29:58 -07:00
if ( io = = 0 ) {
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_STAGE ) {
2010-09-23 16:10:16 -07:00
// output must be specified by AudioPolicyManager when using session
2011-04-19 22:30:36 -07:00
// AUDIO_SESSION_OUTPUT_STAGE
2010-09-23 16:10:16 -07:00
lStatus = BAD_VALUE ;
2010-09-22 14:17:38 -07:00
goto Exit ;
2011-04-19 22:30:36 -07:00
} else if ( sessionId = = AUDIO_SESSION_OUTPUT_MIX ) {
2010-09-23 16:10:16 -07:00
// if the output returned by getOutputForEffect() is removed before we lock the
2011-06-17 21:29:58 -07:00
// mutex below, the call to checkPlaybackThread_l(io) below will detect it
2010-09-23 16:10:16 -07:00
// and we will exit safely
2011-06-17 21:29:58 -07:00
io = AudioSystem : : getOutputForEffect ( & desc ) ;
2010-07-02 08:12:41 -07:00
}
2010-09-23 16:10:16 -07:00
}
{
Mutex : : Autolock _l ( mLock ) ;
2010-07-02 08:12:41 -07:00
2010-06-01 23:49:17 -07:00
if ( ! EffectIsNullUuid ( & pDesc - > uuid ) ) {
// if uuid is specified, request effect descriptor
lStatus = EffectGetDescriptor ( & pDesc - > uuid , & desc ) ;
if ( lStatus < 0 ) {
LOGW ( " createEffect() error %d from EffectGetDescriptor " , lStatus ) ;
goto Exit ;
}
} else {
// if uuid is not specified, look for an available implementation
// of the required type in effect factory
if ( EffectIsNullUuid ( & pDesc - > type ) ) {
LOGW ( " createEffect() no effect type " ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
uint32_t numEffects = 0 ;
effect_descriptor_t d ;
2011-08-02 13:33:41 -07:00
d . flags = 0 ; // prevent compiler warning
2010-06-01 23:49:17 -07:00
bool found = false ;
lStatus = EffectQueryNumberEffects ( & numEffects ) ;
if ( lStatus < 0 ) {
LOGW ( " createEffect() error %d from EffectQueryNumberEffects " , lStatus ) ;
goto Exit ;
}
2010-06-23 17:38:20 -07:00
for ( uint32_t i = 0 ; i < numEffects ; i + + ) {
lStatus = EffectQueryEffect ( i , & desc ) ;
2010-06-01 23:49:17 -07:00
if ( lStatus < 0 ) {
2010-06-23 17:38:20 -07:00
LOGW ( " createEffect() error %d from EffectQueryEffect " , lStatus ) ;
2010-06-01 23:49:17 -07:00
continue ;
}
if ( memcmp ( & desc . type , & pDesc - > type , sizeof ( effect_uuid_t ) ) = = 0 ) {
// If matching type found save effect descriptor. If the session is
// 0 and the effect is not auxiliary, continue enumeration in case
// an auxiliary version of this effect type is available
found = true ;
memcpy ( & d , & desc , sizeof ( effect_descriptor_t ) ) ;
2011-04-19 22:30:36 -07:00
if ( sessionId ! = AUDIO_SESSION_OUTPUT_MIX | |
2010-06-01 23:49:17 -07:00
( desc . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
break ;
}
}
}
if ( ! found ) {
lStatus = BAD_VALUE ;
LOGW ( " createEffect() effect not found " ) ;
goto Exit ;
}
// For same effect type, chose auxiliary version over insert version if
// connect to output mix (Compliance to OpenSL ES)
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_MIX & &
2010-06-01 23:49:17 -07:00
( d . flags & EFFECT_FLAG_TYPE_MASK ) ! = EFFECT_FLAG_TYPE_AUXILIARY ) {
memcpy ( & desc , & d , sizeof ( effect_descriptor_t ) ) ;
}
}
// Do not allow auxiliary effects on a session different from 0 (output mix)
2011-04-19 22:30:36 -07:00
if ( sessionId ! = AUDIO_SESSION_OUTPUT_MIX & &
2010-06-01 23:49:17 -07:00
( desc . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
lStatus = INVALID_OPERATION ;
2010-06-23 17:38:20 -07:00
goto Exit ;
}
2011-07-27 19:49:51 -07:00
// check recording permission for visualizer
if ( ( memcmp ( & desc . type , SL_IID_VISUALIZATION , sizeof ( effect_uuid_t ) ) = = 0 ) & &
! recordingAllowed ( ) ) {
lStatus = PERMISSION_DENIED ;
goto Exit ;
}
2010-06-01 23:49:17 -07:00
// return effect descriptor
memcpy ( pDesc , & desc , sizeof ( effect_descriptor_t ) ) ;
// If output is not specified try to find a matching audio session ID in one of the
// output threads.
2010-09-23 16:10:16 -07:00
// If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
// because of code checking output when entering the function.
2011-06-17 21:29:58 -07:00
// Note: io is never 0 when creating an effect on an input
if ( io = = 0 ) {
2010-09-23 16:10:16 -07:00
// look for the thread where the specified audio session is present
for ( size_t i = 0 ; i < mPlaybackThreads . size ( ) ; i + + ) {
if ( mPlaybackThreads . valueAt ( i ) - > hasAudioSession ( sessionId ) ! = 0 ) {
2011-06-17 21:29:58 -07:00
io = mPlaybackThreads . keyAt ( i ) ;
2010-09-23 16:10:16 -07:00
break ;
2010-07-28 01:32:47 -07:00
}
2010-06-01 23:49:17 -07:00
}
2011-06-17 21:29:58 -07:00
if ( io = = 0 ) {
for ( size_t i = 0 ; i < mRecordThreads . size ( ) ; i + + ) {
if ( mRecordThreads . valueAt ( i ) - > hasAudioSession ( sessionId ) ! = 0 ) {
io = mRecordThreads . keyAt ( i ) ;
break ;
}
}
}
2010-09-23 16:10:16 -07:00
// If no output thread contains the requested session ID, default to
// first output. The effect chain will be moved to the correct output
// thread when a track with the same session ID is created
2011-06-17 21:29:58 -07:00
if ( io = = 0 & & mPlaybackThreads . size ( ) ) {
io = mPlaybackThreads . keyAt ( 0 ) ;
2010-09-23 16:10:16 -07:00
}
2011-06-17 21:29:58 -07:00
LOGV ( " createEffect() got io %d for effect %s " , io , desc . name ) ;
2010-06-01 23:49:17 -07:00
}
2011-06-17 21:29:58 -07:00
ThreadBase * thread = checkRecordThread_l ( io ) ;
2010-06-01 23:49:17 -07:00
if ( thread = = NULL ) {
2011-06-17 21:29:58 -07:00
thread = checkPlaybackThread_l ( io ) ;
if ( thread = = NULL ) {
LOGE ( " createEffect() unknown output thread " ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
2010-06-01 23:49:17 -07:00
}
wclient = mClients . valueFor ( pid ) ;
if ( wclient ! = NULL ) {
client = wclient . promote ( ) ;
} else {
client = new Client ( this , pid ) ;
mClients . add ( pid , client ) ;
}
2011-08-02 13:33:41 -07:00
// create effect on selected output thread
2010-07-13 04:45:46 -07:00
handle = thread - > createEffect_l ( client , effectClient , priority , sessionId ,
& desc , enabled , & lStatus ) ;
2010-06-01 23:49:17 -07:00
if ( handle ! = 0 & & id ! = NULL ) {
* id = handle - > id ( ) ;
}
}
Exit :
if ( status ) {
* status = lStatus ;
}
return handle ;
}
2011-07-27 19:49:51 -07:00
status_t AudioFlinger : : moveEffects ( int sessionId , int srcOutput , int dstOutput )
2010-07-13 04:45:46 -07:00
{
LOGV ( " moveEffects() session %d, srcOutput %d, dstOutput %d " ,
2011-07-27 19:49:51 -07:00
sessionId , srcOutput , dstOutput ) ;
2010-07-13 04:45:46 -07:00
Mutex : : Autolock _l ( mLock ) ;
if ( srcOutput = = dstOutput ) {
LOGW ( " moveEffects() same dst and src outputs %d " , dstOutput ) ;
return NO_ERROR ;
2010-06-23 17:38:20 -07:00
}
2010-07-13 04:45:46 -07:00
PlaybackThread * srcThread = checkPlaybackThread_l ( srcOutput ) ;
if ( srcThread = = NULL ) {
LOGW ( " moveEffects() bad srcOutput %d " , srcOutput ) ;
return BAD_VALUE ;
}
PlaybackThread * dstThread = checkPlaybackThread_l ( dstOutput ) ;
if ( dstThread = = NULL ) {
LOGW ( " moveEffects() bad dstOutput %d " , dstOutput ) ;
return BAD_VALUE ;
2010-06-23 17:38:20 -07:00
}
2010-07-13 04:45:46 -07:00
Mutex : : Autolock _dl ( dstThread - > mLock ) ;
Mutex : : Autolock _sl ( srcThread - > mLock ) ;
2011-07-27 19:49:51 -07:00
moveEffectChain_l ( sessionId , srcThread , dstThread , false ) ;
2010-07-13 04:45:46 -07:00
2010-06-23 17:38:20 -07:00
return NO_ERROR ;
}
2011-08-02 13:33:41 -07:00
// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
2011-07-27 19:49:51 -07:00
status_t AudioFlinger : : moveEffectChain_l ( int sessionId ,
2010-07-13 04:45:46 -07:00
AudioFlinger : : PlaybackThread * srcThread ,
2010-07-28 01:32:47 -07:00
AudioFlinger : : PlaybackThread * dstThread ,
bool reRegister )
2010-07-13 04:45:46 -07:00
{
LOGV ( " moveEffectChain_l() session %d from thread %p to thread %p " ,
2011-07-27 19:49:51 -07:00
sessionId , srcThread , dstThread ) ;
2010-07-13 04:45:46 -07:00
2011-07-27 19:49:51 -07:00
sp < EffectChain > chain = srcThread - > getEffectChain_l ( sessionId ) ;
2010-07-13 04:45:46 -07:00
if ( chain = = 0 ) {
LOGW ( " moveEffectChain_l() effect chain for session %d not on source thread %p " ,
2011-07-27 19:49:51 -07:00
sessionId , srcThread ) ;
2010-07-13 04:45:46 -07:00
return INVALID_OPERATION ;
}
2010-07-28 01:32:47 -07:00
// remove chain first. This is useful only if reconfiguring effect chain on same output thread,
2010-07-13 04:45:46 -07:00
// so that a new chain is created with correct parameters when first effect is added. This is
2011-10-05 17:42:25 -07:00
// otherwise unnecessary as removeEffect_l() will remove the chain when last effect is
2010-07-13 04:45:46 -07:00
// removed.
srcThread - > removeEffectChain_l ( chain ) ;
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
2010-07-28 01:32:47 -07:00
int dstOutput = dstThread - > id ( ) ;
sp < EffectChain > dstChain ;
2011-08-02 13:33:41 -07:00
uint32_t strategy = 0 ; // prevent compiler warning
2010-07-13 04:45:46 -07:00
sp < EffectModule > effect = chain - > getEffectFromId_l ( 0 ) ;
while ( effect ! = 0 ) {
srcThread - > removeEffect_l ( effect ) ;
dstThread - > addEffect_l ( effect ) ;
2011-10-05 17:42:25 -07:00
// removeEffect_l() has stopped the effect if it was active so it must be restarted
if ( effect - > state ( ) = = EffectModule : : ACTIVE | |
effect - > state ( ) = = EffectModule : : STOPPING ) {
effect - > start ( ) ;
}
2010-07-28 01:32:47 -07:00
// if the move request is not received from audio policy manager, the effect must be
// re-registered with the new strategy and output
if ( dstChain = = 0 ) {
dstChain = effect - > chain ( ) . promote ( ) ;
if ( dstChain = = 0 ) {
LOGW ( " moveEffectChain_l() cannot get chain from effect %p " , effect . get ( ) ) ;
srcThread - > addEffect_l ( effect ) ;
return NO_INIT ;
}
strategy = dstChain - > strategy ( ) ;
}
if ( reRegister ) {
AudioSystem : : unregisterEffect ( effect - > id ( ) ) ;
AudioSystem : : registerEffect ( & effect - > desc ( ) ,
dstOutput ,
strategy ,
2011-07-27 19:49:51 -07:00
sessionId ,
2010-07-28 01:32:47 -07:00
effect - > id ( ) ) ;
}
2010-07-13 04:45:46 -07:00
effect = chain - > getEffectFromId_l ( 0 ) ;
}
return NO_ERROR ;
2010-06-23 17:38:20 -07:00
}
2011-06-17 21:29:58 -07:00
2010-06-01 23:49:17 -07:00
// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
2011-06-17 21:29:58 -07:00
sp < AudioFlinger : : EffectHandle > AudioFlinger : : ThreadBase : : createEffect_l (
2010-06-01 23:49:17 -07:00
const sp < AudioFlinger : : Client > & client ,
const sp < IEffectClient > & effectClient ,
int32_t priority ,
int sessionId ,
effect_descriptor_t * desc ,
int * enabled ,
status_t * status
)
{
sp < EffectModule > effect ;
sp < EffectHandle > handle ;
status_t lStatus ;
sp < EffectChain > chain ;
2010-07-13 04:45:46 -07:00
bool chainCreated = false ;
2010-06-01 23:49:17 -07:00
bool effectCreated = false ;
2010-06-23 17:38:20 -07:00
bool effectRegistered = false ;
2010-06-01 23:49:17 -07:00
2011-06-17 21:29:58 -07:00
lStatus = initCheck ( ) ;
if ( lStatus ! = NO_ERROR ) {
2010-06-01 23:49:17 -07:00
LOGW ( " createEffect_l() Audio driver not initialized. " ) ;
goto Exit ;
}
// Do not allow effects with session ID 0 on direct output or duplicating threads
// TODO: add rule for hw accelerated effects on direct outputs with non PCM format
2011-04-19 22:30:36 -07:00
if ( sessionId = = AUDIO_SESSION_OUTPUT_MIX & & mType ! = MIXER ) {
2010-07-13 04:45:46 -07:00
LOGW ( " createEffect_l() Cannot add auxiliary effect %s to session %d " ,
desc - > name , sessionId ) ;
2010-06-01 23:49:17 -07:00
lStatus = BAD_VALUE ;
goto Exit ;
}
2011-06-17 21:29:58 -07:00
// Only Pre processor effects are allowed on input threads and only on input threads
if ( ( mType = = RECORD & &
( desc - > flags & EFFECT_FLAG_TYPE_MASK ) ! = EFFECT_FLAG_TYPE_PRE_PROC ) | |
( mType ! = RECORD & &
( desc - > flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_PRE_PROC ) ) {
LOGW ( " createEffect_l() effect %s (flags %08x) created on wrong thread type %d " ,
desc - > name , desc - > flags , mType ) ;
lStatus = BAD_VALUE ;
goto Exit ;
}
2010-06-01 23:49:17 -07:00
LOGV ( " createEffect_l() thread %p effect %s on session %d " , this , desc - > name , sessionId ) ;
{ // scope for mLock
Mutex : : Autolock _l ( mLock ) ;
// check for existing effect chain with the requested audio session
chain = getEffectChain_l ( sessionId ) ;
if ( chain = = 0 ) {
// create a new chain for this session
LOGV ( " createEffect_l() new effect chain for session %d " , sessionId ) ;
chain = new EffectChain ( this , sessionId ) ;
addEffectChain_l ( chain ) ;
2010-07-13 04:45:46 -07:00
chain - > setStrategy ( getStrategyForSession_l ( sessionId ) ) ;
chainCreated = true ;
2010-06-01 23:49:17 -07:00
} else {
2010-07-15 12:50:15 -07:00
effect = chain - > getEffectFromDesc_l ( desc ) ;
2010-06-01 23:49:17 -07:00
}
LOGV ( " createEffect_l() got effect %p on chain %p " , effect = = 0 ? 0 : effect . get ( ) , chain . get ( ) ) ;
if ( effect = = 0 ) {
2011-06-17 21:29:58 -07:00
int id = mAudioFlinger - > nextUniqueId ( ) ;
2010-06-23 17:38:20 -07:00
// Check CPU and memory usage
2010-07-13 04:45:46 -07:00
lStatus = AudioSystem : : registerEffect ( desc , mId , chain - > strategy ( ) , sessionId , id ) ;
2010-06-23 17:38:20 -07:00
if ( lStatus ! = NO_ERROR ) {
goto Exit ;
}
effectRegistered = true ;
2010-06-01 23:49:17 -07:00
// create a new effect module if none present in the chain
2010-07-13 04:45:46 -07:00
effect = new EffectModule ( this , chain , desc , id , sessionId ) ;
2010-06-01 23:49:17 -07:00
lStatus = effect - > status ( ) ;
if ( lStatus ! = NO_ERROR ) {
goto Exit ;
}
2010-07-15 12:50:15 -07:00
lStatus = chain - > addEffect_l ( effect ) ;
2010-06-01 23:49:17 -07:00
if ( lStatus ! = NO_ERROR ) {
goto Exit ;
}
2010-06-23 17:38:20 -07:00
effectCreated = true ;
2010-06-01 23:49:17 -07:00
effect - > setDevice ( mDevice ) ;
2010-06-23 17:38:20 -07:00
effect - > setMode ( mAudioFlinger - > getMode ( ) ) ;
2010-06-01 23:49:17 -07:00
}
// create effect handle and connect it to effect module
handle = new EffectHandle ( effect , client , effectClient , priority ) ;
lStatus = effect - > addHandle ( handle ) ;
if ( enabled ) {
* enabled = ( int ) effect - > isEnabled ( ) ;
}
}
Exit :
if ( lStatus ! = NO_ERROR & & lStatus ! = ALREADY_EXISTS ) {
2010-07-13 04:45:46 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-06-23 17:38:20 -07:00
if ( effectCreated ) {
2010-07-13 04:45:46 -07:00
chain - > removeEffect_l ( effect ) ;
2010-06-01 23:49:17 -07:00
}
2010-06-23 17:38:20 -07:00
if ( effectRegistered ) {
2010-07-13 04:45:46 -07:00
AudioSystem : : unregisterEffect ( effect - > id ( ) ) ;
}
if ( chainCreated ) {
removeEffectChain_l ( chain ) ;
2010-06-23 17:38:20 -07:00
}
2010-06-01 23:49:17 -07:00
handle . clear ( ) ;
}
if ( status ) {
* status = lStatus ;
}
return handle ;
}
2011-06-17 21:29:58 -07:00
sp < AudioFlinger : : EffectModule > AudioFlinger : : ThreadBase : : getEffect_l ( int sessionId , int effectId )
{
sp < EffectModule > effect ;
sp < EffectChain > chain = getEffectChain_l ( sessionId ) ;
if ( chain ! = 0 ) {
effect = chain - > getEffectFromId_l ( effectId ) ;
}
return effect ;
}
2010-07-13 04:45:46 -07:00
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
// PlaybackThread::mLock held
2011-06-17 21:29:58 -07:00
status_t AudioFlinger : : ThreadBase : : addEffect_l ( const sp < EffectModule > & effect )
2010-07-13 04:45:46 -07:00
{
// check for existing effect chain with the requested audio session
int sessionId = effect - > sessionId ( ) ;
sp < EffectChain > chain = getEffectChain_l ( sessionId ) ;
bool chainCreated = false ;
if ( chain = = 0 ) {
// create a new chain for this session
LOGV ( " addEffect_l() new effect chain for session %d " , sessionId ) ;
chain = new EffectChain ( this , sessionId ) ;
addEffectChain_l ( chain ) ;
chain - > setStrategy ( getStrategyForSession_l ( sessionId ) ) ;
chainCreated = true ;
}
LOGV ( " addEffect_l() %p chain %p effect %p " , this , chain . get ( ) , effect . get ( ) ) ;
if ( chain - > getEffectFromId_l ( effect - > id ( ) ) ! = 0 ) {
LOGW ( " addEffect_l() %p effect %s already present in chain %p " ,
this , effect - > desc ( ) . name , chain . get ( ) ) ;
return BAD_VALUE ;
}
status_t status = chain - > addEffect_l ( effect ) ;
if ( status ! = NO_ERROR ) {
if ( chainCreated ) {
removeEffectChain_l ( chain ) ;
}
return status ;
}
effect - > setDevice ( mDevice ) ;
effect - > setMode ( mAudioFlinger - > getMode ( ) ) ;
return NO_ERROR ;
}
2011-06-17 21:29:58 -07:00
void AudioFlinger : : ThreadBase : : removeEffect_l ( const sp < EffectModule > & effect ) {
2010-07-13 04:45:46 -07:00
LOGV ( " removeEffect_l() %p effect %p " , this , effect . get ( ) ) ;
2010-06-23 17:38:20 -07:00
effect_descriptor_t desc = effect - > desc ( ) ;
2010-07-13 04:45:46 -07:00
if ( ( desc . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
detachAuxEffect_l ( effect - > id ( ) ) ;
}
sp < EffectChain > chain = effect - > chain ( ) . promote ( ) ;
if ( chain ! = 0 ) {
// remove effect chain if removing last effect
if ( chain - > removeEffect_l ( effect ) = = 0 ) {
removeEffectChain_l ( chain ) ;
}
} else {
LOGW ( " removeEffect_l() %p cannot promote chain for effect %p " , this , effect . get ( ) ) ;
}
}
2011-06-17 21:29:58 -07:00
void AudioFlinger : : ThreadBase : : lockEffectChains_l (
Vector < sp < AudioFlinger : : EffectChain > > & effectChains )
{
effectChains = mEffectChains ;
for ( size_t i = 0 ; i < mEffectChains . size ( ) ; i + + ) {
mEffectChains [ i ] - > lock ( ) ;
}
}
void AudioFlinger : : ThreadBase : : unlockEffectChains (
Vector < sp < AudioFlinger : : EffectChain > > & effectChains )
{
for ( size_t i = 0 ; i < effectChains . size ( ) ; i + + ) {
effectChains [ i ] - > unlock ( ) ;
}
}
sp < AudioFlinger : : EffectChain > AudioFlinger : : ThreadBase : : getEffectChain ( int sessionId )
{
Mutex : : Autolock _l ( mLock ) ;
return getEffectChain_l ( sessionId ) ;
}
sp < AudioFlinger : : EffectChain > AudioFlinger : : ThreadBase : : getEffectChain_l ( int sessionId )
{
sp < EffectChain > chain ;
size_t size = mEffectChains . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
if ( mEffectChains [ i ] - > sessionId ( ) = = sessionId ) {
chain = mEffectChains [ i ] ;
break ;
}
}
return chain ;
}
void AudioFlinger : : ThreadBase : : setMode ( uint32_t mode )
{
Mutex : : Autolock _l ( mLock ) ;
size_t size = mEffectChains . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
mEffectChains [ i ] - > setMode_l ( mode ) ;
}
}
void AudioFlinger : : ThreadBase : : disconnectEffect ( const sp < EffectModule > & effect ,
2011-08-02 13:33:41 -07:00
const wp < EffectHandle > & handle ,
bool unpiniflast ) {
2011-07-27 19:49:51 -07:00
2010-06-23 17:38:20 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-07-13 04:45:46 -07:00
LOGV ( " disconnectEffect() %p effect %p " , this , effect . get ( ) ) ;
2010-06-23 17:38:20 -07:00
// delete the effect module if removing last handle on it
if ( effect - > removeHandle ( handle ) = = 0 ) {
2011-08-02 13:33:41 -07:00
if ( ! effect - > isPinned ( ) | | unpiniflast ) {
removeEffect_l ( effect ) ;
AudioSystem : : unregisterEffect ( effect - > id ( ) ) ;
}
2010-06-23 17:38:20 -07:00
}
}
2010-06-01 23:49:17 -07:00
status_t AudioFlinger : : PlaybackThread : : addEffectChain_l ( const sp < EffectChain > & chain )
{
int session = chain - > sessionId ( ) ;
int16_t * buffer = mMixBuffer ;
2010-06-23 17:38:20 -07:00
bool ownsBuffer = false ;
2010-06-01 23:49:17 -07:00
LOGV ( " addEffectChain_l() %p on thread %p for session %d " , chain . get ( ) , this , session ) ;
2010-06-23 17:38:20 -07:00
if ( session > 0 ) {
2010-06-01 23:49:17 -07:00
// Only one effect chain can be present in direct output thread and it uses
// the mix buffer as input
if ( mType ! = DIRECT ) {
size_t numSamples = mFrameCount * mChannelCount ;
buffer = new int16_t [ numSamples ] ;
memset ( buffer , 0 , numSamples * sizeof ( int16_t ) ) ;
LOGV ( " addEffectChain_l() creating new input buffer %p session %d " , buffer , session ) ;
ownsBuffer = true ;
}
2010-06-23 17:38:20 -07:00
// Attach all tracks with same session ID to this chain.
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
sp < Track > track = mTracks [ i ] ;
if ( session = = track - > sessionId ( ) ) {
LOGV ( " addEffectChain_l() track->setMainBuffer track %p buffer %p " , track . get ( ) , buffer ) ;
track - > setMainBuffer ( buffer ) ;
2011-05-09 12:09:06 -07:00
chain - > incTrackCnt ( ) ;
2010-06-23 17:38:20 -07:00
}
2010-06-01 23:49:17 -07:00
}
2010-06-23 17:38:20 -07:00
// indicate all active tracks in the chain
for ( size_t i = 0 ; i < mActiveTracks . size ( ) ; + + i ) {
sp < Track > track = mActiveTracks [ i ] . promote ( ) ;
if ( track = = 0 ) continue ;
if ( session = = track - > sessionId ( ) ) {
LOGV ( " addEffectChain_l() activating track %p on session %d " , track . get ( ) , session ) ;
2011-05-09 12:09:06 -07:00
chain - > incActiveTrackCnt ( ) ;
2010-06-23 17:38:20 -07:00
}
2010-06-01 23:49:17 -07:00
}
}
2010-06-23 17:38:20 -07:00
chain - > setInBuffer ( buffer , ownsBuffer ) ;
chain - > setOutBuffer ( mMixBuffer ) ;
2011-04-19 22:30:36 -07:00
// Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
2010-07-13 04:45:46 -07:00
// chains list in order to be processed last as it contains output stage effects
2011-04-19 22:30:36 -07:00
// Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
// session AUDIO_SESSION_OUTPUT_STAGE to be processed
2010-06-23 17:38:20 -07:00
// after track specific effects and before output stage
2011-04-19 22:30:36 -07:00
// It is therefore mandatory that AUDIO_SESSION_OUTPUT_MIX == 0 and
// that AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX
2010-07-13 04:45:46 -07:00
// Effect chain for other sessions are inserted at beginning of effect
// chains list to be processed before output mix effects. Relative order between other
// sessions is not important
2010-06-23 17:38:20 -07:00
size_t size = mEffectChains . size ( ) ;
size_t i = 0 ;
for ( i = 0 ; i < size ; i + + ) {
if ( mEffectChains [ i ] - > sessionId ( ) < session ) break ;
}
mEffectChains . insertAt ( chain , i ) ;
2011-07-27 19:49:51 -07:00
checkSuspendOnAddEffectChain_l ( chain ) ;
2010-06-23 17:38:20 -07:00
2010-06-01 23:49:17 -07:00
return NO_ERROR ;
}
size_t AudioFlinger : : PlaybackThread : : removeEffectChain_l ( const sp < EffectChain > & chain )
{
int session = chain - > sessionId ( ) ;
LOGV ( " removeEffectChain_l() %p from thread %p for session %d " , chain . get ( ) , this , session ) ;
for ( size_t i = 0 ; i < mEffectChains . size ( ) ; i + + ) {
if ( chain = = mEffectChains [ i ] ) {
mEffectChains . removeAt ( i ) ;
2011-05-09 12:09:06 -07:00
// detach all active tracks from the chain
for ( size_t i = 0 ; i < mActiveTracks . size ( ) ; + + i ) {
sp < Track > track = mActiveTracks [ i ] . promote ( ) ;
if ( track = = 0 ) continue ;
if ( session = = track - > sessionId ( ) ) {
LOGV ( " removeEffectChain_l(): stopping track on chain %p for session Id: %d " ,
chain . get ( ) , session ) ;
chain - > decActiveTrackCnt ( ) ;
}
}
2010-06-01 23:49:17 -07:00
// detach all tracks with same session ID from this chain
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
sp < Track > track = mTracks [ i ] ;
if ( session = = track - > sessionId ( ) ) {
track - > setMainBuffer ( mMixBuffer ) ;
2011-05-09 12:09:06 -07:00
chain - > decTrackCnt ( ) ;
2010-06-01 23:49:17 -07:00
}
}
2010-07-13 04:45:46 -07:00
break ;
2010-06-01 23:49:17 -07:00
}
}
return mEffectChains . size ( ) ;
}
2010-07-13 04:45:46 -07:00
status_t AudioFlinger : : PlaybackThread : : attachAuxEffect (
const sp < AudioFlinger : : PlaybackThread : : Track > track , int EffectId )
2010-06-01 23:49:17 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
return attachAuxEffect_l ( track , EffectId ) ;
}
2010-07-13 04:45:46 -07:00
status_t AudioFlinger : : PlaybackThread : : attachAuxEffect_l (
const sp < AudioFlinger : : PlaybackThread : : Track > track , int EffectId )
2010-06-01 23:49:17 -07:00
{
status_t status = NO_ERROR ;
if ( EffectId = = 0 ) {
track - > setAuxBuffer ( 0 , NULL ) ;
} else {
2011-04-19 22:30:36 -07:00
// Auxiliary effects are always in audio session AUDIO_SESSION_OUTPUT_MIX
sp < EffectModule > effect = getEffect_l ( AUDIO_SESSION_OUTPUT_MIX , EffectId ) ;
2010-06-01 23:49:17 -07:00
if ( effect ! = 0 ) {
if ( ( effect - > desc ( ) . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
track - > setAuxBuffer ( EffectId , ( int32_t * ) effect - > inBuffer ( ) ) ;
} else {
status = INVALID_OPERATION ;
}
} else {
status = BAD_VALUE ;
}
}
return status ;
}
void AudioFlinger : : PlaybackThread : : detachAuxEffect_l ( int effectId )
{
for ( size_t i = 0 ; i < mTracks . size ( ) ; + + i ) {
sp < Track > track = mTracks [ i ] ;
if ( track - > auxEffectId ( ) = = effectId ) {
attachAuxEffect_l ( track , 0 ) ;
}
}
}
2011-06-17 21:29:58 -07:00
status_t AudioFlinger : : RecordThread : : addEffectChain_l ( const sp < EffectChain > & chain )
{
// only one chain per input thread
if ( mEffectChains . size ( ) ! = 0 ) {
return INVALID_OPERATION ;
}
LOGV ( " addEffectChain_l() %p on thread %p " , chain . get ( ) , this ) ;
chain - > setInBuffer ( NULL ) ;
chain - > setOutBuffer ( NULL ) ;
2011-07-27 19:49:51 -07:00
checkSuspendOnAddEffectChain_l ( chain ) ;
2011-06-17 21:29:58 -07:00
mEffectChains . add ( chain ) ;
return NO_ERROR ;
}
size_t AudioFlinger : : RecordThread : : removeEffectChain_l ( const sp < EffectChain > & chain )
{
LOGV ( " removeEffectChain_l() %p from thread %p " , chain . get ( ) , this ) ;
LOGW_IF ( mEffectChains . size ( ) ! = 1 ,
" removeEffectChain_l() %p invalid chain size %d on thread %p " ,
chain . get ( ) , mEffectChains . size ( ) , this ) ;
if ( mEffectChains . size ( ) = = 1 ) {
mEffectChains . removeAt ( 0 ) ;
}
return 0 ;
}
2010-06-01 23:49:17 -07:00
// ----------------------------------------------------------------------------
// EffectModule implementation
// ----------------------------------------------------------------------------
# undef LOG_TAG
# define LOG_TAG "AudioFlinger::EffectModule"
AudioFlinger : : EffectModule : : EffectModule ( const wp < ThreadBase > & wThread ,
const wp < AudioFlinger : : EffectChain > & chain ,
effect_descriptor_t * desc ,
int id ,
int sessionId )
: mThread ( wThread ) , mChain ( chain ) , mId ( id ) , mSessionId ( sessionId ) , mEffectInterface ( NULL ) ,
2011-07-27 19:49:51 -07:00
mStatus ( NO_INIT ) , mState ( IDLE ) , mSuspended ( false )
2010-06-01 23:49:17 -07:00
{
LOGV ( " Constructor %p " , this ) ;
int lStatus ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread = = 0 ) {
return ;
}
memcpy ( & mDescriptor , desc , sizeof ( effect_descriptor_t ) ) ;
// create effect engine from effect factory
2011-06-17 21:29:58 -07:00
mStatus = EffectCreate ( & desc - > uuid , sessionId , thread - > id ( ) , & mEffectInterface ) ;
2010-06-23 17:38:20 -07:00
2010-06-01 23:49:17 -07:00
if ( mStatus ! = NO_ERROR ) {
return ;
}
lStatus = init ( ) ;
if ( lStatus < 0 ) {
mStatus = lStatus ;
goto Error ;
}
2011-08-02 13:33:41 -07:00
if ( mSessionId > AUDIO_SESSION_OUTPUT_MIX ) {
mPinned = true ;
}
2010-06-01 23:49:17 -07:00
LOGV ( " Constructor success name %s, Interface %p " , mDescriptor . name , mEffectInterface ) ;
return ;
Error :
EffectRelease ( mEffectInterface ) ;
mEffectInterface = NULL ;
LOGV ( " Constructor Error %d " , mStatus ) ;
}
AudioFlinger : : EffectModule : : ~ EffectModule ( )
{
LOGV ( " Destructor %p " , this ) ;
if ( mEffectInterface ! = NULL ) {
2011-06-17 21:29:58 -07:00
if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_PRE_PROC | |
( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_POST_PROC ) {
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2011-08-07 16:32:26 -07:00
audio_stream_t * stream = thread - > stream ( ) ;
if ( stream ! = NULL ) {
stream - > remove_audio_effect ( stream , mEffectInterface ) ;
}
2011-06-17 21:29:58 -07:00
}
}
2010-06-01 23:49:17 -07:00
// release effect engine
EffectRelease ( mEffectInterface ) ;
}
}
status_t AudioFlinger : : EffectModule : : addHandle ( sp < EffectHandle > & handle )
{
status_t status ;
Mutex : : Autolock _l ( mLock ) ;
// First handle in mHandles has highest priority and controls the effect module
int priority = handle - > priority ( ) ;
size_t size = mHandles . size ( ) ;
sp < EffectHandle > h ;
size_t i ;
for ( i = 0 ; i < size ; i + + ) {
h = mHandles [ i ] . promote ( ) ;
if ( h = = 0 ) continue ;
if ( h - > priority ( ) < = priority ) break ;
}
// if inserted in first place, move effect control from previous owner to this handle
if ( i = = 0 ) {
2011-07-27 19:49:51 -07:00
bool enabled = false ;
2010-06-01 23:49:17 -07:00
if ( h ! = 0 ) {
2011-07-27 19:49:51 -07:00
enabled = h - > enabled ( ) ;
h - > setControl ( false /*hasControl*/ , true /*signal*/ , enabled /*enabled*/ ) ;
2010-06-01 23:49:17 -07:00
}
2011-07-27 19:49:51 -07:00
handle - > setControl ( true /*hasControl*/ , false /*signal*/ , enabled /*enabled*/ ) ;
2010-06-01 23:49:17 -07:00
status = NO_ERROR ;
} else {
status = ALREADY_EXISTS ;
}
2011-07-27 19:49:51 -07:00
LOGV ( " addHandle() %p added handle %p in position %d " , this , handle . get ( ) , i ) ;
2010-06-01 23:49:17 -07:00
mHandles . insertAt ( handle , i ) ;
return status ;
}
size_t AudioFlinger : : EffectModule : : removeHandle ( const wp < EffectHandle > & handle )
{
Mutex : : Autolock _l ( mLock ) ;
size_t size = mHandles . size ( ) ;
size_t i ;
for ( i = 0 ; i < size ; i + + ) {
if ( mHandles [ i ] = = handle ) break ;
}
if ( i = = size ) {
return size ;
}
2011-07-27 19:49:51 -07:00
LOGV ( " removeHandle() %p removed handle %p in position %d " , this , handle . unsafe_get ( ) , i ) ;
bool enabled = false ;
EffectHandle * hdl = handle . unsafe_get ( ) ;
if ( hdl ) {
LOGV ( " removeHandle() unsafe_get OK " ) ;
enabled = hdl - > enabled ( ) ;
}
2010-06-01 23:49:17 -07:00
mHandles . removeAt ( i ) ;
size = mHandles . size ( ) ;
// if removed from first place, move effect control from this handle to next in line
if ( i = = 0 & & size ! = 0 ) {
sp < EffectHandle > h = mHandles [ 0 ] . promote ( ) ;
if ( h ! = 0 ) {
2011-07-27 19:49:51 -07:00
h - > setControl ( true /*hasControl*/ , true /*signal*/ , enabled /*enabled*/ ) ;
2010-06-01 23:49:17 -07:00
}
}
2011-07-26 20:54:46 -07:00
// Prevent calls to process() and other functions on effect interface from now on.
// The effect engine will be released by the destructor when the last strong reference on
// this object is released which can happen after next process is called.
2011-08-02 13:33:41 -07:00
if ( size = = 0 & & ! mPinned ) {
2011-07-26 20:54:46 -07:00
mState = DESTROYED ;
2010-09-28 14:09:57 -07:00
}
2010-06-01 23:49:17 -07:00
return size ;
}
2011-07-27 19:49:51 -07:00
sp < AudioFlinger : : EffectHandle > AudioFlinger : : EffectModule : : controlHandle ( )
{
Mutex : : Autolock _l ( mLock ) ;
sp < EffectHandle > handle ;
if ( mHandles . size ( ) ! = 0 ) {
handle = mHandles [ 0 ] . promote ( ) ;
}
return handle ;
}
2011-08-02 13:33:41 -07:00
void AudioFlinger : : EffectModule : : disconnect ( const wp < EffectHandle > & handle , bool unpiniflast )
2010-06-01 23:49:17 -07:00
{
2011-07-27 19:49:51 -07:00
LOGV ( " disconnect() %p handle %p " , this , handle . unsafe_get ( ) ) ;
2010-06-01 23:49:17 -07:00
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp < EffectModule > keep ( this ) ;
2010-06-23 17:38:20 -07:00
{
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2011-08-02 13:33:41 -07:00
thread - > disconnectEffect ( keep , handle , unpiniflast ) ;
2010-06-01 23:49:17 -07:00
}
}
}
2010-07-09 13:34:17 -07:00
void AudioFlinger : : EffectModule : : updateState ( ) {
Mutex : : Autolock _l ( mLock ) ;
switch ( mState ) {
case RESTART :
reset_l ( ) ;
// FALL THROUGH
case STARTING :
// clear auxiliary effect input buffer for next accumulation
if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
memset ( mConfig . inputCfg . buffer . raw ,
0 ,
mConfig . inputCfg . buffer . frameCount * sizeof ( int32_t ) ) ;
}
start_l ( ) ;
mState = ACTIVE ;
break ;
case STOPPING :
stop_l ( ) ;
mDisableWaitCnt = mMaxDisableWaitCnt ;
mState = STOPPED ;
break ;
case STOPPED :
// mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the
// turn off sequence.
if ( - - mDisableWaitCnt = = 0 ) {
reset_l ( ) ;
mState = IDLE ;
}
break ;
2011-07-26 20:54:46 -07:00
default : //IDLE , ACTIVE, DESTROYED
2010-07-09 13:34:17 -07:00
break ;
}
}
2010-06-01 23:49:17 -07:00
void AudioFlinger : : EffectModule : : process ( )
{
Mutex : : Autolock _l ( mLock ) ;
2011-07-26 20:54:46 -07:00
if ( mState = = DESTROYED | | mEffectInterface = = NULL | |
2010-07-09 13:34:17 -07:00
mConfig . inputCfg . buffer . raw = = NULL | |
mConfig . outputCfg . buffer . raw = = NULL ) {
2010-06-01 23:49:17 -07:00
return ;
}
2010-08-31 13:50:07 -07:00
if ( isProcessEnabled ( ) ) {
2010-06-01 23:49:17 -07:00
// do 32 bit to 16 bit conversion for auxiliary effect input buffer
if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
AudioMixer : : ditherAndClamp ( mConfig . inputCfg . buffer . s32 ,
mConfig . inputCfg . buffer . s32 ,
2010-07-13 04:45:46 -07:00
mConfig . inputCfg . buffer . frameCount / 2 ) ;
2010-06-01 23:49:17 -07:00
}
// do the actual processing in the effect engine
2010-07-09 13:34:17 -07:00
int ret = ( * mEffectInterface ) - > process ( mEffectInterface ,
& mConfig . inputCfg . buffer ,
& mConfig . outputCfg . buffer ) ;
// force transition to IDLE state when engine is ready
if ( mState = = STOPPED & & ret = = - ENODATA ) {
mDisableWaitCnt = 1 ;
}
2010-06-01 23:49:17 -07:00
// clear auxiliary effect input buffer for next accumulation
if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
2011-01-19 18:36:13 -08:00
memset ( mConfig . inputCfg . buffer . raw , 0 ,
mConfig . inputCfg . buffer . frameCount * sizeof ( int32_t ) ) ;
2010-06-01 23:49:17 -07:00
}
} else if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_INSERT & &
2011-01-19 18:36:13 -08:00
mConfig . inputCfg . buffer . raw ! = mConfig . outputCfg . buffer . raw ) {
// If an insert effect is idle and input buffer is different from output buffer,
// accumulate input onto output
2010-06-01 23:49:17 -07:00
sp < EffectChain > chain = mChain . promote ( ) ;
2011-05-09 12:09:06 -07:00
if ( chain ! = 0 & & chain - > activeTrackCnt ( ) ! = 0 ) {
2011-01-19 18:36:13 -08:00
size_t frameCnt = mConfig . inputCfg . buffer . frameCount * 2 ; //always stereo here
int16_t * in = mConfig . inputCfg . buffer . s16 ;
int16_t * out = mConfig . outputCfg . buffer . s16 ;
for ( size_t i = 0 ; i < frameCnt ; i + + ) {
out [ i ] = clamp16 ( ( int32_t ) out [ i ] + ( int32_t ) in [ i ] ) ;
2010-06-01 23:49:17 -07:00
}
}
}
}
2010-07-02 08:12:41 -07:00
void AudioFlinger : : EffectModule : : reset_l ( )
2010-06-01 23:49:17 -07:00
{
if ( mEffectInterface = = NULL ) {
return ;
}
( * mEffectInterface ) - > command ( mEffectInterface , EFFECT_CMD_RESET , 0 , NULL , 0 , NULL ) ;
}
status_t AudioFlinger : : EffectModule : : configure ( )
{
uint32_t channels ;
if ( mEffectInterface = = NULL ) {
return NO_INIT ;
}
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread = = 0 ) {
return DEAD_OBJECT ;
}
// TODO: handle configuration of effects replacing track process
if ( thread - > channelCount ( ) = = 1 ) {
2011-05-17 19:16:02 -07:00
channels = AUDIO_CHANNEL_OUT_MONO ;
2010-06-01 23:49:17 -07:00
} else {
2011-05-17 19:16:02 -07:00
channels = AUDIO_CHANNEL_OUT_STEREO ;
2010-06-01 23:49:17 -07:00
}
if ( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
2011-05-17 19:16:02 -07:00
mConfig . inputCfg . channels = AUDIO_CHANNEL_OUT_MONO ;
2010-06-01 23:49:17 -07:00
} else {
mConfig . inputCfg . channels = channels ;
}
mConfig . outputCfg . channels = channels ;
2011-05-17 19:16:02 -07:00
mConfig . inputCfg . format = AUDIO_FORMAT_PCM_16_BIT ;
mConfig . outputCfg . format = AUDIO_FORMAT_PCM_16_BIT ;
2010-06-01 23:49:17 -07:00
mConfig . inputCfg . samplingRate = thread - > sampleRate ( ) ;
mConfig . outputCfg . samplingRate = mConfig . inputCfg . samplingRate ;
mConfig . inputCfg . bufferProvider . cookie = NULL ;
mConfig . inputCfg . bufferProvider . getBuffer = NULL ;
mConfig . inputCfg . bufferProvider . releaseBuffer = NULL ;
mConfig . outputCfg . bufferProvider . cookie = NULL ;
mConfig . outputCfg . bufferProvider . getBuffer = NULL ;
mConfig . outputCfg . bufferProvider . releaseBuffer = NULL ;
mConfig . inputCfg . accessMode = EFFECT_BUFFER_ACCESS_READ ;
// Insert effect:
2011-04-19 22:30:36 -07:00
// - in session AUDIO_SESSION_OUTPUT_MIX or AUDIO_SESSION_OUTPUT_STAGE,
2010-07-13 04:45:46 -07:00
// always overwrites output buffer: input buffer == output buffer
2010-06-01 23:49:17 -07:00
// - in other sessions:
// last effect in the chain accumulates in output buffer: input buffer != output buffer
// other effect: overwrites output buffer: input buffer == output buffer
// Auxiliary effect:
// accumulates in output buffer: input buffer != output buffer
// Therefore: accumulate <=> input buffer != output buffer
if ( mConfig . inputCfg . buffer . raw ! = mConfig . outputCfg . buffer . raw ) {
mConfig . outputCfg . accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE ;
} else {
mConfig . outputCfg . accessMode = EFFECT_BUFFER_ACCESS_WRITE ;
}
mConfig . inputCfg . mask = EFFECT_CONFIG_ALL ;
mConfig . outputCfg . mask = EFFECT_CONFIG_ALL ;
mConfig . inputCfg . buffer . frameCount = thread - > frameCount ( ) ;
mConfig . outputCfg . buffer . frameCount = mConfig . inputCfg . buffer . frameCount ;
2010-07-13 04:45:46 -07:00
LOGV ( " configure() %p thread %p buffer %p framecount %d " ,
this , thread . get ( ) , mConfig . inputCfg . buffer . raw , mConfig . inputCfg . buffer . frameCount ) ;
2010-06-01 23:49:17 -07:00
status_t cmdStatus ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( int ) ;
status_t status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_CONFIGURE ,
sizeof ( effect_config_t ) ,
& mConfig ,
& size ,
& cmdStatus ) ;
2010-06-01 23:49:17 -07:00
if ( status = = 0 ) {
status = cmdStatus ;
}
2010-07-09 13:34:17 -07:00
mMaxDisableWaitCnt = ( MAX_DISABLE_TIME_MS * mConfig . outputCfg . samplingRate ) /
( 1000 * mConfig . outputCfg . buffer . frameCount ) ;
2010-06-01 23:49:17 -07:00
return status ;
}
status_t AudioFlinger : : EffectModule : : init ( )
{
2010-07-02 08:12:41 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-06-01 23:49:17 -07:00
if ( mEffectInterface = = NULL ) {
return NO_INIT ;
}
status_t cmdStatus ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( status_t ) ;
status_t status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_INIT ,
0 ,
NULL ,
& size ,
& cmdStatus ) ;
2010-06-01 23:49:17 -07:00
if ( status = = 0 ) {
status = cmdStatus ;
}
return status ;
}
2011-10-05 17:42:25 -07:00
status_t AudioFlinger : : EffectModule : : start ( )
{
Mutex : : Autolock _l ( mLock ) ;
return start_l ( ) ;
}
2010-07-02 08:12:41 -07:00
status_t AudioFlinger : : EffectModule : : start_l ( )
2010-06-01 23:49:17 -07:00
{
if ( mEffectInterface = = NULL ) {
return NO_INIT ;
}
status_t cmdStatus ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( status_t ) ;
status_t status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_ENABLE ,
0 ,
NULL ,
& size ,
& cmdStatus ) ;
2010-06-01 23:49:17 -07:00
if ( status = = 0 ) {
status = cmdStatus ;
}
2011-06-17 21:29:58 -07:00
if ( status = = 0 & &
( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_PRE_PROC | |
( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_POST_PROC ) ) {
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2011-08-07 16:32:26 -07:00
audio_stream_t * stream = thread - > stream ( ) ;
if ( stream ! = NULL ) {
stream - > add_audio_effect ( stream , mEffectInterface ) ;
}
2011-06-17 21:29:58 -07:00
}
}
2010-06-01 23:49:17 -07:00
return status ;
}
2011-07-26 20:54:46 -07:00
status_t AudioFlinger : : EffectModule : : stop ( )
{
Mutex : : Autolock _l ( mLock ) ;
return stop_l ( ) ;
}
2010-07-02 08:12:41 -07:00
status_t AudioFlinger : : EffectModule : : stop_l ( )
2010-06-01 23:49:17 -07:00
{
if ( mEffectInterface = = NULL ) {
return NO_INIT ;
}
status_t cmdStatus ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( status_t ) ;
status_t status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_DISABLE ,
0 ,
NULL ,
& size ,
& cmdStatus ) ;
2010-06-01 23:49:17 -07:00
if ( status = = 0 ) {
status = cmdStatus ;
}
2011-06-17 21:29:58 -07:00
if ( status = = 0 & &
( ( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_PRE_PROC | |
( mDescriptor . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_POST_PROC ) ) {
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread ! = 0 ) {
2011-08-07 16:32:26 -07:00
audio_stream_t * stream = thread - > stream ( ) ;
if ( stream ! = NULL ) {
stream - > remove_audio_effect ( stream , mEffectInterface ) ;
}
2011-06-17 21:29:58 -07:00
}
}
2010-06-01 23:49:17 -07:00
return status ;
}
2010-07-28 05:40:18 -07:00
status_t AudioFlinger : : EffectModule : : command ( uint32_t cmdCode ,
uint32_t cmdSize ,
void * pCmdData ,
uint32_t * replySize ,
void * pReplyData )
2010-06-01 23:49:17 -07:00
{
2010-07-02 08:12:41 -07:00
Mutex : : Autolock _l ( mLock ) ;
// LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
2010-06-01 23:49:17 -07:00
2011-07-26 20:54:46 -07:00
if ( mState = = DESTROYED | | mEffectInterface = = NULL ) {
2010-06-01 23:49:17 -07:00
return NO_INIT ;
}
2010-07-28 05:40:18 -07:00
status_t status = ( * mEffectInterface ) - > command ( mEffectInterface ,
cmdCode ,
cmdSize ,
pCmdData ,
replySize ,
pReplyData ) ;
2010-06-01 23:49:17 -07:00
if ( cmdCode ! = EFFECT_CMD_GET_PARAM & & status = = NO_ERROR ) {
2010-07-28 05:40:18 -07:00
uint32_t size = ( replySize = = NULL ) ? 0 : * replySize ;
2010-06-01 23:49:17 -07:00
for ( size_t i = 1 ; i < mHandles . size ( ) ; i + + ) {
sp < EffectHandle > h = mHandles [ i ] . promote ( ) ;
if ( h ! = 0 ) {
h - > commandExecuted ( cmdCode , cmdSize , pCmdData , size , pReplyData ) ;
}
}
}
return status ;
}
status_t AudioFlinger : : EffectModule : : setEnabled ( bool enabled )
{
2011-08-10 10:37:50 -07:00
2010-06-01 23:49:17 -07:00
Mutex : : Autolock _l ( mLock ) ;
LOGV ( " setEnabled %p enabled %d " , this , enabled ) ;
if ( enabled ! = isEnabled ( ) ) {
2011-08-10 10:37:50 -07:00
status_t status = AudioSystem : : setEffectEnabled ( mId , enabled ) ;
if ( enabled & & status ! = NO_ERROR ) {
return status ;
}
2010-06-01 23:49:17 -07:00
switch ( mState ) {
// going from disabled to enabled
case IDLE :
2010-07-09 13:34:17 -07:00
mState = STARTING ;
break ;
case STOPPED :
mState = RESTART ;
2010-06-01 23:49:17 -07:00
break ;
case STOPPING :
mState = ACTIVE ;
break ;
// going from enabled to disabled
2010-07-09 13:34:17 -07:00
case RESTART :
2010-08-31 13:50:07 -07:00
mState = STOPPED ;
break ;
2010-06-01 23:49:17 -07:00
case STARTING :
2010-07-09 13:34:17 -07:00
mState = IDLE ;
2010-06-01 23:49:17 -07:00
break ;
case ACTIVE :
mState = STOPPING ;
break ;
2011-07-26 20:54:46 -07:00
case DESTROYED :
return NO_ERROR ; // simply ignore as we are being destroyed
2010-06-01 23:49:17 -07:00
}
for ( size_t i = 1 ; i < mHandles . size ( ) ; i + + ) {
sp < EffectHandle > h = mHandles [ i ] . promote ( ) ;
if ( h ! = 0 ) {
h - > setEnabled ( enabled ) ;
}
}
}
return NO_ERROR ;
}
bool AudioFlinger : : EffectModule : : isEnabled ( )
{
switch ( mState ) {
2010-07-09 13:34:17 -07:00
case RESTART :
2010-06-01 23:49:17 -07:00
case STARTING :
case ACTIVE :
return true ;
case IDLE :
case STOPPING :
case STOPPED :
2011-07-26 20:54:46 -07:00
case DESTROYED :
2010-06-01 23:49:17 -07:00
default :
return false ;
}
}
2010-08-31 13:50:07 -07:00
bool AudioFlinger : : EffectModule : : isProcessEnabled ( )
{
switch ( mState ) {
case RESTART :
case ACTIVE :
case STOPPING :
case STOPPED :
return true ;
case IDLE :
case STARTING :
2011-07-26 20:54:46 -07:00
case DESTROYED :
2010-08-31 13:50:07 -07:00
default :
return false ;
}
}
2010-06-01 23:49:17 -07:00
status_t AudioFlinger : : EffectModule : : setVolume ( uint32_t * left , uint32_t * right , bool controller )
{
2010-07-02 08:12:41 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-06-01 23:49:17 -07:00
status_t status = NO_ERROR ;
// Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
// if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
2010-08-31 13:50:07 -07:00
if ( isProcessEnabled ( ) & &
2010-07-19 06:24:46 -07:00
( ( mDescriptor . flags & EFFECT_FLAG_VOLUME_MASK ) = = EFFECT_FLAG_VOLUME_CTRL | |
( mDescriptor . flags & EFFECT_FLAG_VOLUME_MASK ) = = EFFECT_FLAG_VOLUME_IND ) ) {
2010-06-01 23:49:17 -07:00
status_t cmdStatus ;
uint32_t volume [ 2 ] ;
uint32_t * pVolume = NULL ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( volume ) ;
2010-06-01 23:49:17 -07:00
volume [ 0 ] = * left ;
volume [ 1 ] = * right ;
if ( controller ) {
pVolume = volume ;
}
2010-07-28 05:40:18 -07:00
status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_SET_VOLUME ,
size ,
volume ,
& size ,
pVolume ) ;
2010-06-01 23:49:17 -07:00
if ( controller & & status = = NO_ERROR & & size = = sizeof ( volume ) ) {
* left = volume [ 0 ] ;
* right = volume [ 1 ] ;
}
}
return status ;
}
status_t AudioFlinger : : EffectModule : : setDevice ( uint32_t device )
{
2010-07-02 08:12:41 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-06-01 23:49:17 -07:00
status_t status = NO_ERROR ;
2011-06-17 21:29:58 -07:00
if ( device & & ( mDescriptor . flags & EFFECT_FLAG_DEVICE_MASK ) = = EFFECT_FLAG_DEVICE_IND ) {
// audio pre processing modules on RecordThread can receive both output and
// input device indication in the same call
uint32_t dev = device & AUDIO_DEVICE_OUT_ALL ;
if ( dev ) {
status_t cmdStatus ;
uint32_t size = sizeof ( status_t ) ;
status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_SET_DEVICE ,
sizeof ( uint32_t ) ,
& dev ,
& size ,
& cmdStatus ) ;
if ( status = = NO_ERROR ) {
status = cmdStatus ;
}
}
dev = device & AUDIO_DEVICE_IN_ALL ;
if ( dev ) {
status_t cmdStatus ;
uint32_t size = sizeof ( status_t ) ;
status_t status2 = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_SET_INPUT_DEVICE ,
sizeof ( uint32_t ) ,
& dev ,
& size ,
& cmdStatus ) ;
if ( status2 = = NO_ERROR ) {
status2 = cmdStatus ;
}
if ( status = = NO_ERROR ) {
status = status2 ;
}
2010-06-01 23:49:17 -07:00
}
}
return status ;
}
2010-06-23 17:38:20 -07:00
status_t AudioFlinger : : EffectModule : : setMode ( uint32_t mode )
{
2010-07-02 08:12:41 -07:00
Mutex : : Autolock _l ( mLock ) ;
2010-06-23 17:38:20 -07:00
status_t status = NO_ERROR ;
if ( ( mDescriptor . flags & EFFECT_FLAG_AUDIO_MODE_MASK ) = = EFFECT_FLAG_AUDIO_MODE_IND ) {
status_t cmdStatus ;
2010-07-28 05:40:18 -07:00
uint32_t size = sizeof ( status_t ) ;
status = ( * mEffectInterface ) - > command ( mEffectInterface ,
EFFECT_CMD_SET_AUDIO_MODE ,
sizeof ( int ) ,
2011-05-17 19:16:02 -07:00
& mode ,
2010-07-28 05:40:18 -07:00
& size ,
& cmdStatus ) ;
2010-06-23 17:38:20 -07:00
if ( status = = NO_ERROR ) {
status = cmdStatus ;
}
}
return status ;
}
2011-07-27 19:49:51 -07:00
void AudioFlinger : : EffectModule : : setSuspended ( bool suspended )
{
Mutex : : Autolock _l ( mLock ) ;
mSuspended = suspended ;
}
bool AudioFlinger : : EffectModule : : suspended ( )
{
Mutex : : Autolock _l ( mLock ) ;
return mSuspended ;
}
2010-06-01 23:49:17 -07:00
status_t AudioFlinger : : EffectModule : : dump ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
snprintf ( buffer , SIZE , " \t Effect ID %d: \n " , mId ) ;
result . append ( buffer ) ;
bool locked = tryLock ( mLock ) ;
// failed to lock - AudioFlinger is probably deadlocked
if ( ! locked ) {
result . append ( " \t \t Could not lock Fx mutex: \n " ) ;
}
result . append ( " \t \t Session Status State Engine: \n " ) ;
snprintf ( buffer , SIZE , " \t \t %05d %03d %03d 0x%08x \n " ,
mSessionId , mStatus , mState , ( uint32_t ) mEffectInterface ) ;
result . append ( buffer ) ;
result . append ( " \t \t Descriptor: \n " ) ;
snprintf ( buffer , SIZE , " \t \t - UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X \n " ,
mDescriptor . uuid . timeLow , mDescriptor . uuid . timeMid , mDescriptor . uuid . timeHiAndVersion ,
mDescriptor . uuid . clockSeq , mDescriptor . uuid . node [ 0 ] , mDescriptor . uuid . node [ 1 ] , mDescriptor . uuid . node [ 2 ] ,
mDescriptor . uuid . node [ 3 ] , mDescriptor . uuid . node [ 4 ] , mDescriptor . uuid . node [ 5 ] ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " \t \t - TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X \n " ,
mDescriptor . type . timeLow , mDescriptor . type . timeMid , mDescriptor . type . timeHiAndVersion ,
mDescriptor . type . clockSeq , mDescriptor . type . node [ 0 ] , mDescriptor . type . node [ 1 ] , mDescriptor . type . node [ 2 ] ,
mDescriptor . type . node [ 3 ] , mDescriptor . type . node [ 4 ] , mDescriptor . type . node [ 5 ] ) ;
result . append ( buffer ) ;
2011-05-17 19:16:02 -07:00
snprintf ( buffer , SIZE , " \t \t - apiVersion: %08X \n \t \t - flags: %08X \n " ,
2010-06-01 23:49:17 -07:00
mDescriptor . apiVersion ,
mDescriptor . flags ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " \t \t - name: %s \n " ,
mDescriptor . name ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " \t \t - implementor: %s \n " ,
mDescriptor . implementor ) ;
result . append ( buffer ) ;
result . append ( " \t \t - Input configuration: \n " ) ;
result . append ( " \t \t \t Buffer Frames Smp rate Channels Format \n " ) ;
snprintf ( buffer , SIZE , " \t \t \t 0x%08x %05d %05d %08x %d \n " ,
( uint32_t ) mConfig . inputCfg . buffer . raw ,
mConfig . inputCfg . buffer . frameCount ,
mConfig . inputCfg . samplingRate ,
mConfig . inputCfg . channels ,
mConfig . inputCfg . format ) ;
result . append ( buffer ) ;
result . append ( " \t \t - Output configuration: \n " ) ;
result . append ( " \t \t \t Buffer Frames Smp rate Channels Format \n " ) ;
snprintf ( buffer , SIZE , " \t \t \t 0x%08x %05d %05d %08x %d \n " ,
( uint32_t ) mConfig . outputCfg . buffer . raw ,
mConfig . outputCfg . buffer . frameCount ,
mConfig . outputCfg . samplingRate ,
mConfig . outputCfg . channels ,
mConfig . outputCfg . format ) ;
result . append ( buffer ) ;
snprintf ( buffer , SIZE , " \t \t %d Clients: \n " , mHandles . size ( ) ) ;
result . append ( buffer ) ;
result . append ( " \t \t \t Pid Priority Ctrl Locked client server \n " ) ;
for ( size_t i = 0 ; i < mHandles . size ( ) ; + + i ) {
sp < EffectHandle > handle = mHandles [ i ] . promote ( ) ;
if ( handle ! = 0 ) {
handle - > dump ( buffer , SIZE ) ;
result . append ( buffer ) ;
}
}
result . append ( " \n " ) ;
write ( fd , result . string ( ) , result . length ( ) ) ;
if ( locked ) {
mLock . unlock ( ) ;
}
return NO_ERROR ;
}
// ----------------------------------------------------------------------------
// EffectHandle implementation
// ----------------------------------------------------------------------------
# undef LOG_TAG
# define LOG_TAG "AudioFlinger::EffectHandle"
AudioFlinger : : EffectHandle : : EffectHandle ( const sp < EffectModule > & effect ,
const sp < AudioFlinger : : Client > & client ,
const sp < IEffectClient > & effectClient ,
int32_t priority )
: BnEffect ( ) ,
2011-08-02 13:33:41 -07:00
mEffect ( effect ) , mEffectClient ( effectClient ) , mClient ( client ) , mCblk ( NULL ) ,
2011-07-27 19:49:51 -07:00
mPriority ( priority ) , mHasControl ( false ) , mEnabled ( false )
2010-06-01 23:49:17 -07:00
{
LOGV ( " constructor %p " , this ) ;
2011-08-02 13:33:41 -07:00
if ( client = = 0 ) {
return ;
}
2010-06-01 23:49:17 -07:00
int bufOffset = ( ( sizeof ( effect_param_cblk_t ) - 1 ) / sizeof ( int ) + 1 ) * sizeof ( int ) ;
mCblkMemory = client - > heap ( ) - > allocate ( EFFECT_PARAM_BUFFER_SIZE + bufOffset ) ;
if ( mCblkMemory ! = 0 ) {
mCblk = static_cast < effect_param_cblk_t * > ( mCblkMemory - > pointer ( ) ) ;
if ( mCblk ) {
new ( mCblk ) effect_param_cblk_t ( ) ;
mBuffer = ( uint8_t * ) mCblk + bufOffset ;
}
} else {
LOGE ( " not enough memory for Effect size=%u " , EFFECT_PARAM_BUFFER_SIZE + sizeof ( effect_param_cblk_t ) ) ;
return ;
}
}
AudioFlinger : : EffectHandle : : ~ EffectHandle ( )
{
LOGV ( " Destructor %p " , this ) ;
2011-08-02 13:33:41 -07:00
disconnect ( false ) ;
2011-07-27 19:49:51 -07:00
LOGV ( " Destructor DONE %p " , this ) ;
2010-06-01 23:49:17 -07:00
}
status_t AudioFlinger : : EffectHandle : : enable ( )
{
2011-07-27 19:49:51 -07:00
LOGV ( " enable %p " , this ) ;
2010-06-01 23:49:17 -07:00
if ( ! mHasControl ) return INVALID_OPERATION ;
if ( mEffect = = 0 ) return DEAD_OBJECT ;
2011-08-10 10:37:50 -07:00
if ( mEnabled ) {
return NO_ERROR ;
}
2011-07-27 19:49:51 -07:00
mEnabled = true ;
sp < ThreadBase > thread = mEffect - > thread ( ) . promote ( ) ;
if ( thread ! = 0 ) {
thread - > checkSuspendOnEffectEnabled ( mEffect , true , mEffect - > sessionId ( ) ) ;
}
// checkSuspendOnEffectEnabled() can suspend this same effect when enabled
if ( mEffect - > suspended ( ) ) {
return NO_ERROR ;
}
2011-08-10 10:37:50 -07:00
status_t status = mEffect - > setEnabled ( true ) ;
if ( status ! = NO_ERROR ) {
if ( thread ! = 0 ) {
thread - > checkSuspendOnEffectEnabled ( mEffect , false , mEffect - > sessionId ( ) ) ;
}
mEnabled = false ;
}
return status ;
2010-06-01 23:49:17 -07:00
}
status_t AudioFlinger : : EffectHandle : : disable ( )
{
2011-07-27 19:49:51 -07:00
LOGV ( " disable %p " , this ) ;
2010-06-01 23:49:17 -07:00
if ( ! mHasControl ) return INVALID_OPERATION ;
2011-07-27 19:49:51 -07:00
if ( mEffect = = 0 ) return DEAD_OBJECT ;
2010-06-01 23:49:17 -07:00
2011-08-10 10:37:50 -07:00
if ( ! mEnabled ) {
return NO_ERROR ;
}
2011-07-27 19:49:51 -07:00
mEnabled = false ;
if ( mEffect - > suspended ( ) ) {
return NO_ERROR ;
}
status_t status = mEffect - > setEnabled ( false ) ;
sp < ThreadBase > thread = mEffect - > thread ( ) . promote ( ) ;
if ( thread ! = 0 ) {
thread - > checkSuspendOnEffectEnabled ( mEffect , false , mEffect - > sessionId ( ) ) ;
}
return status ;
2010-06-01 23:49:17 -07:00
}
void AudioFlinger : : EffectHandle : : disconnect ( )
{
2011-08-02 13:33:41 -07:00
disconnect ( true ) ;
}
void AudioFlinger : : EffectHandle : : disconnect ( bool unpiniflast )
{
LOGV ( " disconnect(%s) " , unpiniflast ? " true " : " false " ) ;
2010-06-01 23:49:17 -07:00
if ( mEffect = = 0 ) {
return ;
}
2011-08-02 13:33:41 -07:00
mEffect - > disconnect ( this , unpiniflast ) ;
2011-07-27 19:49:51 -07:00
2011-10-19 11:44:54 -07:00
if ( mHasControl & & mEnabled ) {
2011-08-10 10:37:50 -07:00
sp < ThreadBase > thread = mEffect - > thread ( ) . promote ( ) ;
if ( thread ! = 0 ) {
thread - > checkSuspendOnEffectEnabled ( mEffect , false , mEffect - > sessionId ( ) ) ;
}
2011-07-27 19:49:51 -07:00
}
2010-06-01 23:49:17 -07:00
// release sp on module => module destructor can be called now
mEffect . clear ( ) ;
if ( mClient ! = 0 ) {
2011-08-02 13:33:41 -07:00
if ( mCblk ) {
mCblk - > ~ effect_param_cblk_t ( ) ; // destroy our shared-structure.
}
mCblkMemory . clear ( ) ; // and free the shared memory
2010-06-01 23:49:17 -07:00
Mutex : : Autolock _l ( mClient - > audioFlinger ( ) - > mLock ) ;
mClient . clear ( ) ;
}
}
2010-07-28 05:40:18 -07:00
status_t AudioFlinger : : EffectHandle : : command ( uint32_t cmdCode ,
uint32_t cmdSize ,
void * pCmdData ,
uint32_t * replySize ,
void * pReplyData )
2010-06-01 23:49:17 -07:00
{
2010-07-28 05:40:18 -07:00
// LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p",
// cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
2010-06-01 23:49:17 -07:00
// only get parameter command is permitted for applications not controlling the effect
if ( ! mHasControl & & cmdCode ! = EFFECT_CMD_GET_PARAM ) {
return INVALID_OPERATION ;
}
if ( mEffect = = 0 ) return DEAD_OBJECT ;
2011-08-02 13:33:41 -07:00
if ( mClient = = 0 ) return INVALID_OPERATION ;
2010-06-01 23:49:17 -07:00
// handle commands that are not forwarded transparently to effect engine
if ( cmdCode = = EFFECT_CMD_SET_PARAM_COMMIT ) {
// No need to trylock() here as this function is executed in the binder thread serving a particular client process:
// no risk to block the whole media server process or mixer threads is we are stuck here
Mutex : : Autolock _l ( mCblk - > lock ) ;
if ( mCblk - > clientIndex > EFFECT_PARAM_BUFFER_SIZE | |
mCblk - > serverIndex > EFFECT_PARAM_BUFFER_SIZE ) {
mCblk - > serverIndex = 0 ;
mCblk - > clientIndex = 0 ;
return BAD_VALUE ;
}
status_t status = NO_ERROR ;
while ( mCblk - > serverIndex < mCblk - > clientIndex ) {
int reply ;
2010-07-28 05:40:18 -07:00
uint32_t rsize = sizeof ( int ) ;
2010-06-01 23:49:17 -07:00
int * p = ( int * ) ( mBuffer + mCblk - > serverIndex ) ;
int size = * p + + ;
2010-06-23 17:38:20 -07:00
if ( ( ( uint8_t * ) p + size ) > mBuffer + mCblk - > clientIndex ) {
LOGW ( " command(): invalid parameter block size " ) ;
break ;
}
2010-06-01 23:49:17 -07:00
effect_param_t * param = ( effect_param_t * ) p ;
2010-06-23 17:38:20 -07:00
if ( param - > psize = = 0 | | param - > vsize = = 0 ) {
LOGW ( " command(): null parameter or value size " ) ;
mCblk - > serverIndex + = size ;
continue ;
}
2010-07-28 05:40:18 -07:00
uint32_t psize = sizeof ( effect_param_t ) +
( ( param - > psize - 1 ) / sizeof ( int ) + 1 ) * sizeof ( int ) +
param - > vsize ;
status_t ret = mEffect - > command ( EFFECT_CMD_SET_PARAM ,
psize ,
p ,
& rsize ,
& reply ) ;
2010-09-02 11:56:55 -07:00
// stop at first error encountered
if ( ret ! = NO_ERROR ) {
2010-06-01 23:49:17 -07:00
status = ret ;
2010-09-02 11:56:55 -07:00
* ( int * ) pReplyData = reply ;
break ;
} else if ( reply ! = NO_ERROR ) {
* ( int * ) pReplyData = reply ;
break ;
2010-06-01 23:49:17 -07:00
}
mCblk - > serverIndex + = size ;
}
mCblk - > serverIndex = 0 ;
mCblk - > clientIndex = 0 ;
return status ;
} else if ( cmdCode = = EFFECT_CMD_ENABLE ) {
2010-09-02 11:56:55 -07:00
* ( int * ) pReplyData = NO_ERROR ;
2010-06-01 23:49:17 -07:00
return enable ( ) ;
} else if ( cmdCode = = EFFECT_CMD_DISABLE ) {
2010-09-02 11:56:55 -07:00
* ( int * ) pReplyData = NO_ERROR ;
2010-06-01 23:49:17 -07:00
return disable ( ) ;
}
return mEffect - > command ( cmdCode , cmdSize , pCmdData , replySize , pReplyData ) ;
}
sp < IMemory > AudioFlinger : : EffectHandle : : getCblk ( ) const {
return mCblkMemory ;
}
2011-07-27 19:49:51 -07:00
void AudioFlinger : : EffectHandle : : setControl ( bool hasControl , bool signal , bool enabled )
2010-06-01 23:49:17 -07:00
{
LOGV ( " setControl %p control %d " , this , hasControl ) ;
mHasControl = hasControl ;
2011-07-27 19:49:51 -07:00
mEnabled = enabled ;
2010-06-01 23:49:17 -07:00
if ( signal & & mEffectClient ! = 0 ) {
mEffectClient - > controlStatusChanged ( hasControl ) ;
}
}
2010-07-28 05:40:18 -07:00
void AudioFlinger : : EffectHandle : : commandExecuted ( uint32_t cmdCode ,
uint32_t cmdSize ,
void * pCmdData ,
uint32_t replySize ,
void * pReplyData )
2010-06-01 23:49:17 -07:00
{
if ( mEffectClient ! = 0 ) {
mEffectClient - > commandExecuted ( cmdCode , cmdSize , pCmdData , replySize , pReplyData ) ;
}
}
void AudioFlinger : : EffectHandle : : setEnabled ( bool enabled )
{
if ( mEffectClient ! = 0 ) {
mEffectClient - > enableStatusChanged ( enabled ) ;
}
}
status_t AudioFlinger : : EffectHandle : : onTransact (
uint32_t code , const Parcel & data , Parcel * reply , uint32_t flags )
{
return BnEffect : : onTransact ( code , data , reply , flags ) ;
}
void AudioFlinger : : EffectHandle : : dump ( char * buffer , size_t size )
{
2011-08-02 13:33:41 -07:00
bool locked = mCblk ? tryLock ( mCblk - > lock ) : false ;
2010-06-01 23:49:17 -07:00
snprintf ( buffer , size , " \t \t \t %05d %05d %01u %01u %05u %05u \n " ,
( mClient = = NULL ) ? getpid ( ) : mClient - > pid ( ) ,
mPriority ,
mHasControl ,
! locked ,
2011-08-02 13:33:41 -07:00
mCblk ? mCblk - > clientIndex : 0 ,
mCblk ? mCblk - > serverIndex : 0
2010-06-01 23:49:17 -07:00
) ;
if ( locked ) {
mCblk - > lock . unlock ( ) ;
}
}
# undef LOG_TAG
# define LOG_TAG "AudioFlinger::EffectChain"
AudioFlinger : : EffectChain : : EffectChain ( const wp < ThreadBase > & wThread ,
int sessionId )
2011-05-09 12:09:06 -07:00
: mThread ( wThread ) , mSessionId ( sessionId ) , mActiveTrackCnt ( 0 ) , mTrackCnt ( 0 ) ,
mOwnInBuffer ( false ) , mVolumeCtrlIdx ( - 1 ) , mLeftVolume ( UINT_MAX ) , mRightVolume ( UINT_MAX ) ,
mNewLeftVolume ( UINT_MAX ) , mNewRightVolume ( UINT_MAX )
2010-06-01 23:49:17 -07:00
{
2011-04-19 22:30:36 -07:00
mStrategy = AudioSystem : : getStrategyForStream ( AUDIO_STREAM_MUSIC ) ;
2010-06-01 23:49:17 -07:00
}
AudioFlinger : : EffectChain : : ~ EffectChain ( )
{
if ( mOwnInBuffer ) {
delete mInBuffer ;
}
}
2011-07-27 19:49:51 -07:00
// getEffectFromDesc_l() must be called with ThreadBase::mLock held
2010-07-15 12:50:15 -07:00
sp < AudioFlinger : : EffectModule > AudioFlinger : : EffectChain : : getEffectFromDesc_l ( effect_descriptor_t * descriptor )
2010-06-01 23:49:17 -07:00
{
sp < EffectModule > effect ;
size_t size = mEffects . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
if ( memcmp ( & mEffects [ i ] - > desc ( ) . uuid , & descriptor - > uuid , sizeof ( effect_uuid_t ) ) = = 0 ) {
effect = mEffects [ i ] ;
break ;
}
}
return effect ;
}
2011-07-27 19:49:51 -07:00
// getEffectFromId_l() must be called with ThreadBase::mLock held
2010-07-15 12:50:15 -07:00
sp < AudioFlinger : : EffectModule > AudioFlinger : : EffectChain : : getEffectFromId_l ( int id )
2010-06-01 23:49:17 -07:00
{
sp < EffectModule > effect ;
size_t size = mEffects . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
2010-07-13 04:45:46 -07:00
// by convention, return first effect if id provided is 0 (0 is never a valid id)
if ( id = = 0 | | mEffects [ i ] - > id ( ) = = id ) {
2010-06-01 23:49:17 -07:00
effect = mEffects [ i ] ;
break ;
}
}
return effect ;
}
2011-07-27 19:49:51 -07:00
// getEffectFromType_l() must be called with ThreadBase::mLock held
sp < AudioFlinger : : EffectModule > AudioFlinger : : EffectChain : : getEffectFromType_l (
const effect_uuid_t * type )
{
sp < EffectModule > effect ;
size_t size = mEffects . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
if ( memcmp ( & mEffects [ i ] - > desc ( ) . type , type , sizeof ( effect_uuid_t ) ) = = 0 ) {
effect = mEffects [ i ] ;
break ;
}
}
return effect ;
}
2010-06-01 23:49:17 -07:00
// Must be called with EffectChain::mLock locked
void AudioFlinger : : EffectChain : : process_l ( )
{
2010-09-28 14:09:57 -07:00
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread = = 0 ) {
LOGW ( " process_l(): cannot promote mixer thread " ) ;
return ;
}
2011-04-19 22:30:36 -07:00
bool isGlobalSession = ( mSessionId = = AUDIO_SESSION_OUTPUT_MIX ) | |
( mSessionId = = AUDIO_SESSION_OUTPUT_STAGE ) ;
2010-09-28 14:09:57 -07:00
bool tracksOnSession = false ;
if ( ! isGlobalSession ) {
2011-05-09 12:09:06 -07:00
tracksOnSession = ( trackCnt ( ) ! = 0 ) ;
}
// if no track is active, input buffer must be cleared here as the mixer process
// will not do it
if ( tracksOnSession & &
activeTrackCnt ( ) = = 0 ) {
2011-06-17 21:29:58 -07:00
size_t numSamples = thread - > frameCount ( ) * thread - > channelCount ( ) ;
2011-05-09 12:09:06 -07:00
memset ( mInBuffer , 0 , numSamples * sizeof ( int16_t ) ) ;
2010-09-28 14:09:57 -07:00
}
2010-06-01 23:49:17 -07:00
size_t size = mEffects . size ( ) ;
2010-09-28 14:09:57 -07:00
// do not process effect if no track is present in same audio session
if ( isGlobalSession | | tracksOnSession ) {
for ( size_t i = 0 ; i < size ; i + + ) {
mEffects [ i ] - > process ( ) ;
}
2010-06-01 23:49:17 -07:00
}
2010-07-09 13:34:17 -07:00
for ( size_t i = 0 ; i < size ; i + + ) {
mEffects [ i ] - > updateState ( ) ;
}
2010-06-01 23:49:17 -07:00
}
2010-07-15 12:50:15 -07:00
// addEffect_l() must be called with PlaybackThread::mLock held
2010-07-13 04:45:46 -07:00
status_t AudioFlinger : : EffectChain : : addEffect_l ( const sp < EffectModule > & effect )
2010-06-01 23:49:17 -07:00
{
effect_descriptor_t desc = effect - > desc ( ) ;
uint32_t insertPref = desc . flags & EFFECT_FLAG_INSERT_MASK ;
Mutex : : Autolock _l ( mLock ) ;
2010-07-13 04:45:46 -07:00
effect - > setChain ( this ) ;
sp < ThreadBase > thread = mThread . promote ( ) ;
if ( thread = = 0 ) {
return NO_INIT ;
}
effect - > setThread ( thread ) ;
2010-06-01 23:49:17 -07:00
if ( ( desc . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) {
// Auxiliary effects are inserted at the beginning of mEffects vector as
// they are processed first and accumulated in chain input buffer
mEffects . insertAt ( effect , 0 ) ;
2010-07-13 04:45:46 -07:00
2010-06-01 23:49:17 -07:00
// the input buffer for auxiliary effect contains mono samples in
// 32 bit format. This is to avoid saturation in AudoMixer
// accumulation stage. Saturation is done in EffectModule::process() before
// calling the process in effect engine
size_t numSamples = thread - > frameCount ( ) ;
int32_t * buffer = new int32_t [ numSamples ] ;
memset ( buffer , 0 , numSamples * sizeof ( int32_t ) ) ;
effect - > setInBuffer ( ( int16_t * ) buffer ) ;
// auxiliary effects output samples to chain input buffer for further processing
// by insert effects
effect - > setOutBuffer ( mInBuffer ) ;
} else {
// Insert effects are inserted at the end of mEffects vector as they are processed
// after track and auxiliary effects.
2010-06-23 17:38:20 -07:00
// Insert effect order as a function of indicated preference:
// if EFFECT_FLAG_INSERT_EXCLUSIVE, insert in first position or reject if
// another effect is present
// else if EFFECT_FLAG_INSERT_FIRST, insert in first position or after the
// last effect claiming first position
// else if EFFECT_FLAG_INSERT_LAST, insert in last position or before the
// first effect claiming last position
2010-06-01 23:49:17 -07:00
// else if EFFECT_FLAG_INSERT_ANY insert after first or before last
2010-06-23 17:38:20 -07:00
// Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
// already present
2010-06-01 23:49:17 -07:00
int size = ( int ) mEffects . size ( ) ;
int idx_insert = size ;
int idx_insert_first = - 1 ;
int idx_insert_last = - 1 ;
for ( int i = 0 ; i < size ; i + + ) {
effect_descriptor_t d = mEffects [ i ] - > desc ( ) ;
uint32_t iMode = d . flags & EFFECT_FLAG_TYPE_MASK ;
uint32_t iPref = d . flags & EFFECT_FLAG_INSERT_MASK ;
if ( iMode = = EFFECT_FLAG_TYPE_INSERT ) {
// check invalid effect chaining combinations
if ( insertPref = = EFFECT_FLAG_INSERT_EXCLUSIVE | |
2010-06-23 17:38:20 -07:00
iPref = = EFFECT_FLAG_INSERT_EXCLUSIVE ) {
2010-07-15 12:50:15 -07:00
LOGW ( " addEffect_l() could not insert effect %s: exclusive conflict with %s " , desc . name , d . name ) ;
2010-06-01 23:49:17 -07:00
return INVALID_OPERATION ;
}
2010-06-23 17:38:20 -07:00
// remember position of first insert effect and by default
// select this as insert position for new effect
2010-06-01 23:49:17 -07:00
if ( idx_insert = = size ) {
idx_insert = i ;
}
2010-06-23 17:38:20 -07:00
// remember position of last insert effect claiming
// first position
2010-06-01 23:49:17 -07:00
if ( iPref = = EFFECT_FLAG_INSERT_FIRST ) {
idx_insert_first = i ;
}
2010-06-23 17:38:20 -07:00
// remember position of first insert effect claiming
// last position
if ( iPref = = EFFECT_FLAG_INSERT_LAST & &
idx_insert_last = = - 1 ) {
2010-06-01 23:49:17 -07:00
idx_insert_last = i ;
}
}
}
2010-06-23 17:38:20 -07:00
// modify idx_insert from first position if needed
if ( insertPref = = EFFECT_FLAG_INSERT_LAST ) {
if ( idx_insert_last ! = - 1 ) {
idx_insert = idx_insert_last ;
} else {
idx_insert = size ;
}
} else {
if ( idx_insert_first ! = - 1 ) {
idx_insert = idx_insert_first + 1 ;
}
2010-06-01 23:49:17 -07:00
}
// always read samples from chain input buffer
effect - > setInBuffer ( mInBuffer ) ;
// if last effect in the chain, output samples to chain
// output buffer, otherwise to chain input buffer
if ( idx_insert = = size ) {
if ( idx_insert ! = 0 ) {
mEffects [ idx_insert - 1 ] - > setOutBuffer ( mInBuffer ) ;
mEffects [ idx_insert - 1 ] - > configure ( ) ;
}
effect - > setOutBuffer ( mOutBuffer ) ;
} else {
effect - > setOutBuffer ( mInBuffer ) ;
}
2010-06-23 17:38:20 -07:00
mEffects . insertAt ( effect , idx_insert ) ;
2010-06-01 23:49:17 -07:00
2010-07-15 12:50:15 -07:00
LOGV ( " addEffect_l() effect %p, added in chain %p at rank %d " , effect . get ( ) , this , idx_insert ) ;
2010-06-01 23:49:17 -07:00
}
effect - > configure ( ) ;
return NO_ERROR ;
}
2010-07-15 12:50:15 -07:00
// removeEffect_l() must be called with PlaybackThread::mLock held
size_t AudioFlinger : : EffectChain : : removeEffect_l ( const sp < EffectModule > & effect )
2010-06-01 23:49:17 -07:00
{
Mutex : : Autolock _l ( mLock ) ;
int size = ( int ) mEffects . size ( ) ;
int i ;
uint32_t type = effect - > desc ( ) . flags & EFFECT_FLAG_TYPE_MASK ;
for ( i = 0 ; i < size ; i + + ) {
if ( effect = = mEffects [ i ] ) {
2011-07-26 20:54:46 -07:00
// calling stop here will remove pre-processing effect from the audio HAL.
// This is safe as we hold the EffectChain mutex which guarantees that we are not in
// the middle of a read from audio HAL
2011-10-05 17:42:25 -07:00
if ( mEffects [ i ] - > state ( ) = = EffectModule : : ACTIVE | |
mEffects [ i ] - > state ( ) = = EffectModule : : STOPPING ) {
mEffects [ i ] - > stop ( ) ;
}
2010-06-01 23:49:17 -07:00
if ( type = = EFFECT_FLAG_TYPE_AUXILIARY ) {
delete [ ] effect - > inBuffer ( ) ;
} else {
if ( i = = size - 1 & & i ! = 0 ) {
mEffects [ i - 1 ] - > setOutBuffer ( mOutBuffer ) ;
mEffects [ i - 1 ] - > configure ( ) ;
}
}
mEffects . removeAt ( i ) ;
2010-07-15 12:50:15 -07:00
LOGV ( " removeEffect_l() effect %p, removed from chain %p at rank %d " , effect . get ( ) , this , i ) ;
2010-06-01 23:49:17 -07:00
break ;
}
}
return mEffects . size ( ) ;
}
2010-07-15 12:50:15 -07:00
// setDevice_l() must be called with PlaybackThread::mLock held
void AudioFlinger : : EffectChain : : setDevice_l ( uint32_t device )
2010-06-01 23:49:17 -07:00
{
size_t size = mEffects . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
mEffects [ i ] - > setDevice ( device ) ;
}
}
2010-07-15 12:50:15 -07:00
// setMode_l() must be called with PlaybackThread::mLock held
void AudioFlinger : : EffectChain : : setMode_l ( uint32_t mode )
2010-06-23 17:38:20 -07:00
{
size_t size = mEffects . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + ) {
mEffects [ i ] - > setMode ( mode ) ;
}
}
2010-07-15 12:50:15 -07:00
// setVolume_l() must be called with PlaybackThread::mLock held
bool AudioFlinger : : EffectChain : : setVolume_l ( uint32_t * left , uint32_t * right )
2010-06-01 23:49:17 -07:00
{
uint32_t newLeft = * left ;
uint32_t newRight = * right ;
bool hasControl = false ;
2010-07-15 12:50:15 -07:00
int ctrlIdx = - 1 ;
size_t size = mEffects . size ( ) ;
2010-06-01 23:49:17 -07:00
2010-07-15 12:50:15 -07:00
// first update volume controller
for ( size_t i = size ; i > 0 ; i - - ) {
2010-08-31 13:50:07 -07:00
if ( mEffects [ i - 1 ] - > isProcessEnabled ( ) & &
2010-07-15 12:50:15 -07:00
( mEffects [ i - 1 ] - > desc ( ) . flags & EFFECT_FLAG_VOLUME_MASK ) = = EFFECT_FLAG_VOLUME_CTRL ) {
ctrlIdx = i - 1 ;
2010-07-19 06:24:46 -07:00
hasControl = true ;
2010-07-15 12:50:15 -07:00
break ;
}
}
if ( ctrlIdx = = mVolumeCtrlIdx & & * left = = mLeftVolume & & * right = = mRightVolume ) {
2010-07-19 06:24:46 -07:00
if ( hasControl ) {
* left = mNewLeftVolume ;
* right = mNewRightVolume ;
}
return hasControl ;
2010-07-15 12:50:15 -07:00
}
mVolumeCtrlIdx = ctrlIdx ;
2010-07-19 06:24:46 -07:00
mLeftVolume = newLeft ;
mRightVolume = newRight ;
2010-07-15 12:50:15 -07:00
// second get volume update from volume controller
if ( ctrlIdx > = 0 ) {
mEffects [ ctrlIdx ] - > setVolume ( & newLeft , & newRight , true ) ;
2010-07-19 06:24:46 -07:00
mNewLeftVolume = newLeft ;
mNewRightVolume = newRight ;
2010-06-01 23:49:17 -07:00
}
// then indicate volume to all other effects in chain.
// Pass altered volume to effects before volume controller
// and requested volume to effects after controller
uint32_t lVol = newLeft ;
uint32_t rVol = newRight ;
2010-07-15 12:50:15 -07:00
2010-06-01 23:49:17 -07:00
for ( size_t i = 0 ; i < size ; i + + ) {
2010-07-15 12:50:15 -07:00
if ( ( int ) i = = ctrlIdx ) continue ;
// this also works for ctrlIdx == -1 when there is no volume controller
if ( ( int ) i > ctrlIdx ) {
2010-06-01 23:49:17 -07:00
lVol = * left ;
rVol = * right ;
}
mEffects [ i ] - > setVolume ( & lVol , & rVol , false ) ;
}
* left = newLeft ;
* right = newRight ;
return hasControl ;
}
status_t AudioFlinger : : EffectChain : : dump ( int fd , const Vector < String16 > & args )
{
const size_t SIZE = 256 ;
char buffer [ SIZE ] ;
String8 result ;
snprintf ( buffer , SIZE , " Effects for session %d: \n " , mSessionId ) ;
result . append ( buffer ) ;
bool locked = tryLock ( mLock ) ;
// failed to lock - AudioFlinger is probably deadlocked
if ( ! locked ) {
result . append ( " \t Could not lock mutex: \n " ) ;
}
2010-07-15 12:50:15 -07:00
result . append ( " \t Num fx In buffer Out buffer Active tracks: \n " ) ;
snprintf ( buffer , SIZE , " \t %02d 0x%08x 0x%08x %d \n " ,
2010-06-01 23:49:17 -07:00
mEffects . size ( ) ,
( uint32_t ) mInBuffer ,
( uint32_t ) mOutBuffer ,
mActiveTrackCnt ) ;
result . append ( buffer ) ;
write ( fd , result . string ( ) , result . size ( ) ) ;
for ( size_t i = 0 ; i < mEffects . size ( ) ; + + i ) {
sp < EffectModule > effect = mEffects [ i ] ;
if ( effect ! = 0 ) {
effect - > dump ( fd , args ) ;
}
}
if ( locked ) {
mLock . unlock ( ) ;
}
return NO_ERROR ;
}
2011-07-27 19:49:51 -07:00
// must be called with ThreadBase::mLock held
void AudioFlinger : : EffectChain : : setEffectSuspended_l (
const effect_uuid_t * type , bool suspend )
{
sp < SuspendedEffectDesc > desc ;
// use effect type UUID timelow as key as there is no real risk of identical
// timeLow fields among effect type UUIDs.
int index = mSuspendedEffects . indexOfKey ( type - > timeLow ) ;
if ( suspend ) {
if ( index > = 0 ) {
desc = mSuspendedEffects . valueAt ( index ) ;
} else {
desc = new SuspendedEffectDesc ( ) ;
memcpy ( & desc - > mType , type , sizeof ( effect_uuid_t ) ) ;
mSuspendedEffects . add ( type - > timeLow , desc ) ;
LOGV ( " setEffectSuspended_l() add entry for %08x " , type - > timeLow ) ;
}
if ( desc - > mRefCount + + = = 0 ) {
sp < EffectModule > effect = getEffectIfEnabled ( type ) ;
if ( effect ! = 0 ) {
desc - > mEffect = effect ;
effect - > setSuspended ( true ) ;
effect - > setEnabled ( false ) ;
}
}
} else {
if ( index < 0 ) {
return ;
}
desc = mSuspendedEffects . valueAt ( index ) ;
if ( desc - > mRefCount < = 0 ) {
LOGW ( " setEffectSuspended_l() restore refcount should not be 0 %d " , desc - > mRefCount ) ;
desc - > mRefCount = 1 ;
}
if ( - - desc - > mRefCount = = 0 ) {
LOGV ( " setEffectSuspended_l() remove entry for %08x " , mSuspendedEffects . keyAt ( index ) ) ;
if ( desc - > mEffect ! = 0 ) {
sp < EffectModule > effect = desc - > mEffect . promote ( ) ;
if ( effect ! = 0 ) {
effect - > setSuspended ( false ) ;
sp < EffectHandle > handle = effect - > controlHandle ( ) ;
if ( handle ! = 0 ) {
effect - > setEnabled ( handle - > enabled ( ) ) ;
}
}
desc - > mEffect . clear ( ) ;
}
mSuspendedEffects . removeItemsAt ( index ) ;
}
}
}
// must be called with ThreadBase::mLock held
void AudioFlinger : : EffectChain : : setEffectSuspendedAll_l ( bool suspend )
{
sp < SuspendedEffectDesc > desc ;
int index = mSuspendedEffects . indexOfKey ( ( int ) kKeyForSuspendAll ) ;
if ( suspend ) {
if ( index > = 0 ) {
desc = mSuspendedEffects . valueAt ( index ) ;
} else {
desc = new SuspendedEffectDesc ( ) ;
mSuspendedEffects . add ( ( int ) kKeyForSuspendAll , desc ) ;
LOGV ( " setEffectSuspendedAll_l() add entry for 0 " ) ;
}
if ( desc - > mRefCount + + = = 0 ) {
Vector < sp < EffectModule > > effects = getSuspendEligibleEffects ( ) ;
for ( size_t i = 0 ; i < effects . size ( ) ; i + + ) {
setEffectSuspended_l ( & effects [ i ] - > desc ( ) . type , true ) ;
}
}
} else {
if ( index < 0 ) {
return ;
}
desc = mSuspendedEffects . valueAt ( index ) ;
if ( desc - > mRefCount < = 0 ) {
LOGW ( " setEffectSuspendedAll_l() restore refcount should not be 0 %d " , desc - > mRefCount ) ;
desc - > mRefCount = 1 ;
}
if ( - - desc - > mRefCount = = 0 ) {
Vector < const effect_uuid_t * > types ;
for ( size_t i = 0 ; i < mSuspendedEffects . size ( ) ; i + + ) {
if ( mSuspendedEffects . keyAt ( i ) = = ( int ) kKeyForSuspendAll ) {
continue ;
}
types . add ( & mSuspendedEffects . valueAt ( i ) - > mType ) ;
}
for ( size_t i = 0 ; i < types . size ( ) ; i + + ) {
setEffectSuspended_l ( types [ i ] , false ) ;
}
LOGV ( " setEffectSuspendedAll_l() remove entry for %08x " , mSuspendedEffects . keyAt ( index ) ) ;
mSuspendedEffects . removeItem ( ( int ) kKeyForSuspendAll ) ;
}
}
}
2011-09-23 08:40:41 -07:00
// The volume effect is used for automated tests only
# ifndef OPENSL_ES_H_
static const effect_uuid_t SL_IID_VOLUME_ = { 0x09e8ede0 , 0xddde , 0x11db , 0xb4f6 ,
{ 0x00 , 0x02 , 0xa5 , 0xd5 , 0xc5 , 0x1b } } ;
const effect_uuid_t * const SL_IID_VOLUME = & SL_IID_VOLUME_ ;
# endif //OPENSL_ES_H_
2011-08-10 10:37:50 -07:00
bool AudioFlinger : : EffectChain : : isEffectEligibleForSuspend ( const effect_descriptor_t & desc )
{
// auxiliary effects and visualizer are never suspended on output mix
if ( ( mSessionId = = AUDIO_SESSION_OUTPUT_MIX ) & &
( ( ( desc . flags & EFFECT_FLAG_TYPE_MASK ) = = EFFECT_FLAG_TYPE_AUXILIARY ) | |
2011-09-23 08:40:41 -07:00
( memcmp ( & desc . type , SL_IID_VISUALIZATION , sizeof ( effect_uuid_t ) ) = = 0 ) | |
( memcmp ( & desc . type , SL_IID_VOLUME , sizeof ( effect_uuid_t ) ) = = 0 ) ) ) {
2011-08-10 10:37:50 -07:00
return false ;
}
return true ;
}
2011-07-27 19:49:51 -07:00
Vector < sp < AudioFlinger : : EffectModule > > AudioFlinger : : EffectChain : : getSuspendEligibleEffects ( )
{
Vector < sp < EffectModule > > effects ;
for ( size_t i = 0 ; i < mEffects . size ( ) ; i + + ) {
2011-08-10 10:37:50 -07:00
if ( ! isEffectEligibleForSuspend ( mEffects [ i ] - > desc ( ) ) ) {
2011-07-27 19:49:51 -07:00
continue ;
}
effects . add ( mEffects [ i ] ) ;
}
return effects ;
}
sp < AudioFlinger : : EffectModule > AudioFlinger : : EffectChain : : getEffectIfEnabled (
const effect_uuid_t * type )
{
sp < EffectModule > effect ;
effect = getEffectFromType_l ( type ) ;
if ( effect ! = 0 & & ! effect - > isEnabled ( ) ) {
effect . clear ( ) ;
}
return effect ;
}
void AudioFlinger : : EffectChain : : checkSuspendOnEffectEnabled ( const sp < EffectModule > & effect ,
bool enabled )
{
int index = mSuspendedEffects . indexOfKey ( effect - > desc ( ) . type . timeLow ) ;
if ( enabled ) {
if ( index < 0 ) {
// if the effect is not suspend check if all effects are suspended
index = mSuspendedEffects . indexOfKey ( ( int ) kKeyForSuspendAll ) ;
if ( index < 0 ) {
return ;
}
2011-08-10 10:37:50 -07:00
if ( ! isEffectEligibleForSuspend ( effect - > desc ( ) ) ) {
return ;
}
2011-07-27 19:49:51 -07:00
setEffectSuspended_l ( & effect - > desc ( ) . type , enabled ) ;
index = mSuspendedEffects . indexOfKey ( effect - > desc ( ) . type . timeLow ) ;
2011-08-10 10:37:50 -07:00
if ( index < 0 ) {
LOGW ( " checkSuspendOnEffectEnabled() Fx should be suspended here! " ) ;
return ;
}
2011-07-27 19:49:51 -07:00
}
LOGV ( " checkSuspendOnEffectEnabled() enable suspending fx %08x " ,
effect - > desc ( ) . type . timeLow ) ;
sp < SuspendedEffectDesc > desc = mSuspendedEffects . valueAt ( index ) ;
// if effect is requested to suspended but was not yet enabled, supend it now.
if ( desc - > mEffect = = 0 ) {
desc - > mEffect = effect ;
effect - > setEnabled ( false ) ;
effect - > setSuspended ( true ) ;
}
} else {
if ( index < 0 ) {
return ;
}
LOGV ( " checkSuspendOnEffectEnabled() disable restoring fx %08x " ,
effect - > desc ( ) . type . timeLow ) ;
sp < SuspendedEffectDesc > desc = mSuspendedEffects . valueAt ( index ) ;
desc - > mEffect . clear ( ) ;
effect - > setSuspended ( false ) ;
}
}
2010-06-01 23:49:17 -07:00
# undef LOG_TAG
# define LOG_TAG "AudioFlinger"
2009-07-17 12:17:14 -07:00
// ----------------------------------------------------------------------------
2008-10-21 07:00:00 -07:00
status_t AudioFlinger : : onTransact (
uint32_t code , const Parcel & data , Parcel * reply , uint32_t flags )
{
return BnAudioFlinger : : onTransact ( code , data , reply , flags ) ;
}
} ; // namespace android