Eric Laurent 421ddc014b Fix issue 3439872: video chat and bluetooth SCO
This change fixes the stability problems experienced when using
a bluetooth headset supporting both A2DP and SCO. Problems occur
when starting the video chat at which time the A2DP output is being
stopped to start SCO. At that time, active AudioTracks are invalidated
by AudioFlinger so that a new AudioTrack binder interface can be
recreated by the client process on the new mixer thread with correct parameters.
The problem was that the process to restore the binder interface was not
protected against concurrent requests which caused 2 binder interfaces
to be created sometimes. This could lead to permanent client deadlock
if one of the client threads was waiting for a condition of the first
created binder interface while the second one was created (as the AudioFlinger
would only signal conditions on the last one created).
This concurrent request situation is more likely to happen when a client
uses the JAVA AudioTrack as the JNI implementation uses simultaneously the
native AudioTrack callback and write push mechanisms. By doing so, the code
that checks if the binder interface should be restored (in obtainBuffer()) is
much more likely to be called concurrently from two different threads.

The fix consists in protecting the critical binder interface restore phase
with a flag in the AudioTrack control block. The first thread acting upon the binder
interface restore request will raise the flag and the second thread will just wait for
a condition to be signaled when the restore process is complete.

Also protected all accesses to the AudioTrack control block by a mutex to prevent
access while the track is being destroyed and restored. If a mutex cannot be held
(e.g because we call a callback function), acquire a strong reference on the IAudioTrack
to prevent its destruction while the cblk is being accessed.

Modified AudioTrack JNI to use GetByteArrayElements() instead of
GetPrimitiveArrayCritical() when writing audio buffers. Entering a critical section would
cause the JNI to abort if a mediaserver crash occurs during a write due to the AudioSystem
callback being called during the critical section when media server process restarts.
Anyway with current JNI implementation, either versions do not copy data most of the times
and the criticial version does not guaranty no data copy.

The same modifications have been made to AudioRecord.

Change-Id: Idc5aa711a04c3eee180cdd03f44fe17f3c4dcb52
2011-03-08 16:33:15 -08:00

109 lines
4.5 KiB
C++

/*
* Copyright (C) 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.
*/
#ifndef ANDROID_AUDIO_TRACK_SHARED_H
#define ANDROID_AUDIO_TRACK_SHARED_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
namespace android {
// ----------------------------------------------------------------------------
#define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
// Maximum cumulated timeout milliseconds before restarting audioflinger thread
#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
#define MAX_RUN_TIMEOUT_MS 1000
#define WAIT_PERIOD_MS 10
#define RESTORE_TIMEOUT_MS 5000 // Maximum waiting time for a track to be restored
#define CBLK_UNDERRUN_MSK 0x0001
#define CBLK_UNDERRUN_ON 0x0001 // underrun (out) or overrrun (in) indication
#define CBLK_UNDERRUN_OFF 0x0000 // no underrun
#define CBLK_DIRECTION_MSK 0x0002
#define CBLK_DIRECTION_OUT 0x0002 // this cblk is for an AudioTrack
#define CBLK_DIRECTION_IN 0x0000 // this cblk is for an AudioRecord
#define CBLK_FORCEREADY_MSK 0x0004
#define CBLK_FORCEREADY_ON 0x0004 // track is considered ready immediately by AudioFlinger
#define CBLK_FORCEREADY_OFF 0x0000 // track is ready when buffer full
#define CBLK_INVALID_MSK 0x0008
#define CBLK_INVALID_ON 0x0008 // track buffer is invalidated by AudioFlinger:
#define CBLK_INVALID_OFF 0x0000 // must be re-created
#define CBLK_DISABLED_MSK 0x0010
#define CBLK_DISABLED_ON 0x0010 // track disabled by AudioFlinger due to underrun:
#define CBLK_DISABLED_OFF 0x0000 // must be re-started
#define CBLK_RESTORING_MSK 0x0020
#define CBLK_RESTORING_ON 0x0020 // track is being restored after invalidation
#define CBLK_RESTORING_OFF 0x0000 // by AudioFlinger
#define CBLK_RESTORED_MSK 0x0040
#define CBLK_RESTORED_ON 0x0040 // track has been restored after invalidation
#define CBLK_RESTORED_OFF 0x0040 // by AudioFlinger
struct audio_track_cblk_t
{
// The data members are grouped so that members accessed frequently and in the same context
// are in the same line of data cache.
Mutex lock;
Condition cv;
volatile uint32_t user;
volatile uint32_t server;
uint32_t userBase;
uint32_t serverBase;
void* buffers;
uint32_t frameCount;
// Cache line boundary
uint32_t loopStart;
uint32_t loopEnd;
int loopCount;
volatile union {
uint16_t volume[2];
uint32_t volumeLR;
};
uint32_t sampleRate;
// NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
// 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer
uint8_t frameSize;
uint8_t channelCount;
uint16_t flags;
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time
uint16_t sendLevel;
uint16_t reserved;
// Cache line boundary (32 bytes)
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);
bool stepServer(uint32_t frameCount);
void* buffer(uint32_t offset) const;
uint32_t framesAvailable();
uint32_t framesAvailable_l();
uint32_t framesReady();
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_AUDIO_TRACK_SHARED_H