Commit Graph

131 Commits

Author SHA1 Message Date
Eric Laurent
4edfe75018 Fix issue 2553359: Pandora does not work well with Passion deskdock / Cardock.
The problem is due to a too big difference between the buffer size used at the hardware interface and at the A2DP interface.
When no resampling occurs we don't notice problems but the timing is very tight. As soon as resampling is activated, the AudioTrack underruns.
This is because the AudioTrack buffers are not resized when moving the AudioTrack from hardware to A2DP output.
The AudioTrack buffers are calculated based on a hardware output buffer size of 3072 bytes. Which is much less than the A2DP output buffer size (10240).

The solution consists in creating new tracks with new buffers in AudioFlinger when the A2DP output is opened
instead of just transfering active tracks from hardware output mixer thread to the new A2DP output mixer thread.
To avoid synchronization issues between mixer threads and client processes, this is done by invalidating tracks
by setting a flag in their control block and having AudioTrack release the handle on this track (IAudioTrack)
and create a new IAudioTrack when this flag is detected next time obtainBuffer() or start() is executed.

AudioFlinger modifications:
- invalidate the tracks when setStreamOutput() is called
- make sure that notifications of output opening/closing and change of stream type to output mapping are sent synchronously to client process.
This is necessary so that AudioSystem has the new stream to output mapping when the AudioTrack detects the invalidate flag in the client process.
Previously their were sent when the corresponding thread loop was executed.

AudioTrack modifications:
- move frame count calculation and verification from set() to createTrack() so that is is updated every time a new IAudioTrack is created.
- detect track invalidate flag in obtainBuffer() and start() and create a new IAudioTrack.

AudioTrackShared modifications
- group all flags (out, flowControlFlag, forceReady...) into a single bit filed to save space.

Change-Id: I9ac26b6192230627d35084e1449640caaf7d56ee
2010-05-17 02:23:47 -07:00
Eric Laurent
e151216d38 AudioFlinger: rename variables to clarify reference to track channel count or channel mask
Some variables and structure members should be renamed to reflect the fact that they contain the
number of channels in a track (channel count) or the actual channels used by a track (channel mask).
Especially member "channels" of track control block (struct audio_track_cblk_t) is actually the
number of channels (channels count).

Change-Id: I220c8dede9fc00c8a5693389e790073b6ed307b8
2010-05-14 05:45:46 -07:00
Eric Laurent
7232215a17 Merge "Fix issue 2678048: binder death detection in AudioFlinger is broken." into kraken 2010-05-12 23:40:28 -07:00
Eric Laurent
cb720e9611 Several fixes in AudioDumpInterface:
- forward setMode() and getInputBufferSize() calls to underlying audio hardware interface.
- Allow capture of more than one output stream (previous implementation was only capturing
the first output opened, namely the hardware output).
- Allow capture of input streams: previous implementation was only simulating input streams
when more than one was open at a time by reading from a file on SD card). Now the default
behavior is to capture PCM data read from input stream if it was successfully opened or
simulate capture otherwise.

Change-Id: I7e2892b25e295fc3c19c7eb0f71bfaea5816b73a
2010-05-12 08:31:04 -07:00
Eric Laurent
d878cd8a79 Fix issue 2678048: binder death detection in AudioFlinger is broken.
There is a bug in the way notification client list is managed when the client binder
interface dies that makes that the dead client is not removed from the list: the week
reference passed by binderDied() cannot be promoted and compared to the strong
references in the list.

The fix consists in creating a new NotificationClient class that implements the
binder DeathRecipient and holds a strong reference to the IAudioFlingerClient interface.
A new instance of this class is created for each cient and a strong reference to this
object is added to the notification client list maintained by AudioFlinger.
When binderDied() is called on this object, it is removed from the list preventing
AudioFlinger to notify this client for further io changes.

Also added code to disable LifeVibes effects when the client that has enabled the
enhancements dies.

Change-Id: Icedc4af171759e9ae9a575d82d44784b4e8267e8
2010-05-12 06:29:16 -07:00
Jean-Michel Trivi
e783275aca Fix bug 2604132 40s skip after undocking
In case of A2DP write errors, there is an overflow in the calculation
of the sleep duration to simulate the timing of a successful write.

Change-Id: Ic4e570aebf07fac69735aab1bbc2fc73512ee795
2010-04-20 12:12:13 -07:00
Eric Laurent
775fa3cd32 Additional fix for isssue 2548710: Native AudioTrack resources never freed.
This changes fixes the issue for the direct output thread that was not
addressed by commit 71f37cd8a175ee00635cb91506d6810fd02b5b51.

Change-Id: I1bbe26be5f444415dd97270e49257650f5d2858f
2010-04-09 06:11:48 -07:00
Eric Laurent
deea502a92 Fix isssue 2548710: Native AudioTrack resources never freed.
The problem is a bug in AudioFlinger::MixerThread::prepareTracks_l() that makes that even if the TrackHandle
is destroyed, the corresponding Track will remain active as long as frames are ready for mixing.
If the track uses shared memory (static mode) and the sound is looped, this track will play for ever.

The fix consists in removing the track from active list immediately if the track is terminated.

Change-Id: I4582aa1d981079ab79be442fb6185f5afaed5cf3
2010-03-31 12:36:34 -07:00
Eric Laurent
101e77a31b Fix issue 2416481: Support Voice Dialer over BT SCO.
- AudioPolicyManager: allow platform specific choice for opening a direct output.
 Also fixed problems in direct output management.
- AudioFliinger: use shorter standby delay and track inactivity grace period for direct output
thread to free hardware resources as soon as possible.
- AudioSystem: do not use cached output selection in getOutput() when a direct output
can be selected.

Change-Id: If44b50d29237b8402ffd7a5ba1dc43c56f903e9b
2010-03-16 17:32:18 -07:00
Jean-Michel Trivi
08abf1fa13 Fix bug 2203203 Route STREAM_VOICE_CALL to A2DP when not in call.
Change-Id: I5581702780308658415dc4ad19fbe409fdc5c368
2010-03-14 10:55:57 -07:00
Jean-Baptiste Queru
e4623e8754 Use proper config to enable LVMX
Change-Id: Ifa75a82884b99aeee139e055f40e7c510cf28213
2010-03-09 18:13:59 -08:00
Glenn Kasten
d5ea969b41 Initial version of LifeVibes integration.
Also changed tabs to spaces in other audioflinger files.
2010-03-09 14:16:01 -08:00
Jean-Michel Trivi
84cf7d9e88 Fix bug 2329540
Part 1 of the fix: when the user doesn't elect to use the car dock
 for music and media, the APM was not aware of the device being
 docked.
 This is fixed by dissociating the notification for the APM of
 the docking to the dock from the sink state change of the A2DP
 device.
 Also missing was forcing the volumes to be reevaluated whenever
 the device is docked or undocked, as volumes for docks may
 differ, even when the same output device is being used.

Change-Id: If5314e27821a71adbd6df6fdf887c45208241d96
2010-03-09 12:45:55 -08:00
Eric Laurent
219795f5d0 Fix issue 2317760: Change the priority between wired headset and A2DP.
Modified audio policy manager so that wired headset has precedence over A2DP headset.
2010-03-08 06:50:44 -08:00
Eric Laurent
4f1fcc2890 Fix issue 2428563: Camera rendered inoperable by voice call interruption.
The problem is that AudioRecord never exits read() when a timeout occurs while trying
to get new PCM data from audio hardware input buffer: it just keeps waiting and retrying until stop() is called.
In the same time, opencore AndroidAudioInput::audin_thread_func() loop cannot be exited when stuck
in AudioRecord::read() because the iExitAudioThread flag can only be sampled when AudioRecord::read()
returns. We remain stuck with the audio input thread running.

The fix consists in modifying AudioRecord behavior in case of timeout when getting new PCM samples.
We now wait only one timeout period and try to restart audio record, in case the problem is due to a media_server
process crash. If this fails, we exit read() with a number of bytes read equals to 0 so that
AndroidAudioInput::audin_thread_func() loop can exit.

Also modified Audioflinger::RecordThread() loop so that we attempt to recover from HAL read errors.
In case of read error, the input stream is forced to standby so that next read attempt does a
reconfiguration and restart of the audio input device.
2010-03-05 11:54:23 -08:00
Eric Laurent
134ccbd131 Issue 2071329: audio track is shorter than video track for video capture on sholes
Add API to retrieve number of frames dropped by audio input kernel driver.

Submitted on behalf of Masaki Sato <masaki.sato@motorola.com>
2010-03-02 08:20:13 -08:00
Eric Laurent
15498d6a23 Fix issue 2327064: Music played via line out is interrupted due to the phone call audio on BT hs.
This is not a real fix for the issue but a change to make sure that the behavior is consistent regardless of
external condidions (WIFI ON or OFF, music started before call or not, A2DP device same as SCO device...).

As there is now way to guaranty good quality audio over both SCO and A2DP simultaneously, especially when WIFI is on, We will stick to this behavior:
When music is playing and we are docked to the desk dock and a call is answered with a BT SCO headset, A2DP output will be suspended.
If music is restarted during the call, it will appear muted to the user until the call is terminated.
2010-02-24 11:54:32 -08:00
Eric Laurent
34248170a7 Fix issue 2305382: Pick up original call makes a noisy beep when wired headset connected.
The noise is the residual ring tone that is still playing while the call is answered and the
audio route changed to headset or earpiece.

The fix consists in muting the ringing tone when changing mode from ringtone to in call
and delaying the route change until the audio buffers are emptied.
2010-02-23 11:00:56 -08:00
Mathias Agopian
0dd0d2944a Simplify the MemoryDealer implementation
At some point the implementation became complicated because of
SurfaceFlinger's special needs, since we are now relying on gralloc
we can go back to much simpler MemoryDealer.

Removed HeapInterface and AllocatorInterface, since those don't need
to be paramterized anymore. Merged SimpleMemory and Allocation.
Made SimplisticAllocator non virtual.

Removed MemoryDealer flags (READ_ONLY, PAGE_ALIGNED)

Removed a lot of unneeded code.
2010-01-29 14:51:06 -08:00
Eric Laurent
7ccc09a4f3 Remove verbose log from AudioPolicyManagerBase. 2010-01-28 13:42:59 -08:00
Eric Laurent
e9ed2721f4 Fix issue 2285561: New AudioFlinger and audio driver API needed for A/V sync
Added getRenderPosition() API to IAudioFlinger to retreive number of audio frames
written by AudioFlinger to audio HAL and by DSP to DAC.

Added getRenderPosition() API to AudioHardwareInterface to retreive number of audio frames
written by DSP to DAC.

Exposed AudioTrack::getPosition() to AudioSink() to make it available to media player.

Removed excessive log in AudioHardwareGeneric.
2010-01-26 18:40:39 -08:00
Eric Laurent
43c0b0a1f6 Fix issue 2378022: AudioService should direct volume control to STREAM_VOICE_CALL stream when STREAM_VOICE_CALL stream is active.
Modified AudioService.getActiveStreamType() so that STREAM_VOICE_CALL is selected when a track using this stream
type is playing.

Chanded isMusicActive() for a more generic isStreamActive(stream) method in AudioSystem, IAudioFlinger and AudioFlinger.
2010-01-25 14:00:10 -08:00
Eric Laurent
da3529b468 Create base class for audio policy manager.
First implementations of audio policy manager in Eclair branch have shown that most code is common to all platforms.
Creating AudioPolicyManagerBase base class will improve code maintainability and readability.

Audio policy manager code for platforms using generic audio previously in AudioPolicyManagerGeneric is replaced by AudioPolicyManagerBase.
Audio policy manager test code previously in AudioPolicyManagerGeneric is moved to AudioPolicyManagerBase.

Also added a wake lock for delayed commands in AudioPolicyService.
2010-01-13 09:25:13 -08:00
Eric Laurent
8a468f2fd6 am 0c5cc224: am d20a55af: Merge change Iccfa50fe into eclair
Merge commit '0c5cc224b052654ee38d39effce427a47697481b'

* commit '0c5cc224b052654ee38d39effce427a47697481b':
  Fix issue 2323920: Notification & A2DP audio stutter.
2009-12-22 10:01:39 -08:00
Eric Laurent
7e2aad1e27 Fix issue 2323920: Notification & A2DP audio stutter.
Modified AudioFlinger duplicating output thread so that audio tracks are not mixed until both outputs (A2DP and hardware) have exited standby mode. This avoids to have one output far ahead of the other and audio frames dropped because the compensation mechanism cannot keep up.
Also calculate the maximum wait time in OutputTrack::write() based the on smallest frame count of all output threads instead of the frame count of the thread the OutputTrack is connected to. This avoids starving the thread with the smallest frame count by waiting too long on the other thread.
Since the frame count was reduced on hardware output to reduce latency the difference between A2DP and hardware outputs frame counts had become problematic.
Also increased the number of overflow buffers to cope with bigger timing differences among outputs.
2009-12-22 09:06:46 -08:00
Eric Laurent
7749a90e1e am 0a08029f: Fix issue 2306779: Runtime restart - Init failed at android.media.ToneGenerator.
Merge commit '0a08029fc9a370c6ef2a2a6fd1d800d9159b61f8' into eclair-mr2

* commit '0a08029fc9a370c6ef2a2a6fd1d800d9159b61f8':
  Fix issue  2306779: Runtime restart - Init failed at android.media.ToneGenerator.
2009-12-07 12:36:30 -08:00
Eric Laurent
fed9382a6a Fix issue 2306779: Runtime restart - Init failed at android.media.ToneGenerator.
The ToneGenerator failed to initialize because no more tracks were available in AudioFlinger mixer.

All tracks were used because the duplicating output was failing to free the tracks on audio hardware output mixer when exiting due to a misplaced test on output activity: output tracks where only freed if the duplicating output was active when exiting.

The fix consists in freeing the output tracks when the duplicating thread is destroyed without condition.
2009-12-07 12:30:22 -08:00
Eric Laurent
8aaf9a21bc am 6d42d806: Merge change I9cc489a2 into eclair
Merge commit '6d42d80653f2c41f3e72a878a1d9a6f9693b89f7' into eclair-mr2

* commit '6d42d80653f2c41f3e72a878a1d9a6f9693b89f7':
  Fix issue 2304669: VoiceIME: starting and canceling voice IME yields persistent "error 8" state on future attempts and breaks voice search.
2009-12-07 11:03:17 -08:00
Eric Laurent
5291095089 Fix issue 2304669: VoiceIME: starting and canceling voice IME yields persistent "error 8" state on future attempts and breaks voice search.
Fixed AudioFlinger::openInput() broken in change ddb78e7753be03937ad57ce7c3c842c52bdad65e
so that an invalid IO handle (0) is returned in case of failure.
Applied the same correction to openOutput().
Modified RecordThread start procedure so that a failure occuring during the first read from audio input stream is detected and causes
the record start to fail.
Modified RecordThread stop procedure to make sure that audio input stream fd is closed before we exit the stop function.

Fixed AudioRecord JAVA and JNI implementation to take status of native AudioRecord::start() into account
and not change mRecordingState to RECORDSTATE_RECORDING if start fails.
2009-12-07 05:37:47 -08:00
Eric Laurent
b598e9f38d am 1ac56b60: Merge change Iac196e17 into eclair
Merge commit '1ac56b602aa6a1ac54c608e5a8b76f44638db23b' into eclair-mr2

* commit '1ac56b602aa6a1ac54c608e5a8b76f44638db23b':
  Fix issue 2292062: Audio freezes for three seconds when choosing ringtones with a headset connected and music playing.
2009-12-02 09:48:52 -08:00
Eric Laurent
d3fc8ac6c5 Fix issue 2292062: Audio freezes for three seconds when choosing ringtones with a headset connected and music playing.
The problem comes from a deadlock with AudioPolicyService mutex: When the second ringtone starts,
this mutex is locked by AudioPolicyService::startOutput() which in turn calls setParameters() to change the output device.
Audioflinger::ThreadBase::setParameters() signals the parameter change to the AudioFlinger mixer thread and waits for a condition
indicating that the parameter change has been processed.
At the same time, the mixer thread detects that the audio track corresponding to the first ring tone has been killed and calls its destructor.
This calls AudioPolicyService::releaseOutput() which tries to lock the AudioPolicyService mutex.
If this happens before the mixer thread can process the setParameters() command we are deadlocked.
The deadlock ends because setParameters() uses a timeout when waiting for the condition.

This regression was introduced by change 33736 fixing issue 2265163.

The fix consists in calling AudioPolicyService::releaseOutput() from Track::destroy() instead of from Track destructor: as detroy() is never called from the mixer thread loop (as opposed to the destructor) the deadlock described above cannot occur.
2009-12-01 02:17:41 -08:00
Eric Laurent
760971d097 Fix A2dpAudioInterface getParameters.
A2dpAudioInterface::getParameters() was prepending a ';' to the key value pair returned from underlying AudioHardwareInterface.
2009-11-25 06:08:44 -08:00
Eric Laurent
09b4ba82d7 Issue 2265163: Audio still reported routed through earpiece on sholes
This is a second attempt to fix the audio routed to earpiece syndrom.
The root cause identified this time is the crash of an application having an active AudioTrack playing on the VOICE_CALL stream type.
When this happens, the AudioTrack destructor is not called and the audio policy manager is not notified of the track stop.
Results a situation where the VOICE_CALL stream is considered as always in use by audio policy manager which makes that audio is routed to earpiece.

The fix consists in moving the track start/stop/close notification to audio policiy manager from AudioTrack to AudioFlinger Track objet.
The net result is that in the case of a client application crash, the AudioFlinger TrackHandle object (which implements the remote side of the IAudioTrack binder interface) destructor is called which in turn destroys the Track object and we can notify the audio policy manager of the track stop and removal.

The same modification is made for AudioRecord although no bug related to record has been reported yet.
Also fixed a potential problem if record stop is called while the record thread is exiting.
2009-11-19 23:57:45 -08:00
Eric Laurent
0e49d35fa4 Improvements for issue 2197683: English IME key-press latency is noticeably higher on passion than sholes
This change goes with a kernel driver change that reduces the audio buffer size from 4800 bytes (~27ms) to 3072 bytes (~17ms).
- The AudioFlinger modifcations in change 0bca68cfff161abbc992fec82dc7c88079dd1a36 have been removed: the short sleep period was counter productive when the AudioTrack is using the call back thread as it causes to many preemptions.
- AudioFlinger mixer thread now detects long standby exit time and in this case anticipates start by writing 0s as soon as a track is enabled even if not ready for mixing.
- AudioTrack::start() is modified to start call back thread before starting the IAudioTrack so that thread startup time is masked by IAudioTrack start and mixer thread wakeup time.
2009-11-11 12:13:27 -08:00
Eric Laurent
7b57085a73 AudioFlinger: delete Track object when createTrack() fails due to lack of tracks in AudioMixer.
This problem was encountered as a side effect of issue 2245298.
2009-11-09 04:45:39 -08:00
Eric Laurent
ee47d43ed3 More log for issue 2242381.
Added more log in system dump for AudioFlinger and AudioPolicyService to help debug issue 2242381 and other issues where the audio driver hangs.
2009-11-07 01:18:20 -08:00
Eric Laurent
7f698b4c5c Log for issue 2203561.
Implemented AudioPolicyService dump().
Added detailed dump for AudioPolicyManageriGeneric when AudioPolicyService is dumped.
2009-11-03 09:33:35 -08:00
Eric Laurent
134aa9c942 Fix issue 197683: English IME key-press latency is noticeably higher on passion than sholes. Part 2.
Reduce sleep time in AudioFlinger mixer thread when no data has been written to output to speed up startup time when  exiting standby.

The rest of the modifications for this issues is in kernel driver:
 commit 0dbb0ee136ed8de757df1ae26d84556c1751deae for buffer size modification from 8192 to 4800 bytes.
Another kernel improvement that is not submitted yes will reduce delay when audio output is exiting standby.
2009-11-02 00:13:56 -08:00
Eric Laurent
63da2b65f9 Fix issue 2192181: AudioFlinger must provide separated methods to set VOICE_CALL stream volume and down link audio volume.
Added setVoiceVolume() method to AudioSystem, AudioFlinger, IAudioFlinger, AudioPolicyService.
Removed call to AudioHardwareInterface::setVoiceVolume() from AudioFlinger::setStreamVolume().
2009-10-21 12:29:37 -07:00
Eric Laurent
2115412564 Fix issue 2174002: After rejecting Call when device ringtone is mute and playing music, audio is not transfered to BT device.
Added a workarouond to request the A2DP output standby directly to audio hardware when the sink is suspended as it seems that the suspend request often fails.

Also take into account resume requests received while a suspend request is pending.
2009-10-08 12:03:51 -07:00
Eric Laurent
f5e868baf9 Fix issue 2139634: DTMF tones on Sholes popping, hissing (audio latency too high).
This change is a complement to the main fix in kernel driver for the same issue (partner change #1250).
It removes clicks sometimes heard after the end of the tones while audio flinger is sending 0s to the audio output stream.
The problem was that the sleep time between two writes was more than the duration of one audio output stream buffer which could cause some underrun.

Also fixed a recent regression in ToneGenerator that made that the end of previous tone was repeated at the beginning of current one under certain timing circumstances when the maximum tone duration was specified.
2009-10-06 18:59:35 -07:00
Eric Laurent
2d70c80a7f Fix issue 2153835: AudioFlinger: setParameters() can remain stuck if output thread is terminated.
Wait for the parameter set completed condition with a time out in ThreadBase::setParameters().
Also lock AudioFlinger mutex before accessing thread list in AudioFlinger::setParameters() and keep a strong reference
on the thread being used in case it is exited while processing the request.
2009-09-30 14:48:20 -07:00
Dave Sparks
8a95a45fd9 Reduce the log spew from AudioFlinger due to a certain device that can't meet latency timing. Bug 2142215. 2009-09-30 03:09:03 -07:00
Eric Laurent
aef692f50f Fix issue 2116700: Ringer screwy while connected over Bluetooth.
There was a regression introduced in AudioFlinger by change 24114 for suspended output:
The suspended output was not reading and mixing audio tracks.
When the phone is ringing, the A2DP output is suspended if the SCO headset and A2DP headset are the same. As the ringtone is played over the duplicated output, the fact that the A2DP output was not reading data was causing the hardware output to be stalled from time to time.
2009-09-22 00:35:48 -07:00
Eric Laurent
0f8ab670c0 Fix issue 2127371: Possible race condition in AudioFlinger::openRecord() when a Track is being destroyed.
The fix consists in locking AudioFlinger::mLock mutex in the TrackBase destructor before clearing the strong pointer to the shared memory client. The mutex is not locked in removeclient() any more which implies that we must make sure that the Client destructor is always called from the TrackBase destructor or that we hold the mLock mutex before calling deleting the Client.
2009-09-17 09:26:04 -07:00
Eric Laurent
bdc0f84793 Fix issue 2123668: Class scope typo in AudioFlinger.cpp. 2009-09-16 06:02:45 -07:00
Eric Laurent
b3687ae925 Fix issue 2118464: cannot play ring tones and notifications after disconnecting BT headset while in call.
The problem comes from the fact that when the duplicated output is closed after BT headset disconnection, the OUTPUT_CLOSED notification is not sent to AudioSystem. Then the mapping between notification stream and duplicated output cached in AudioSystem is not cleared and next time a notification is played, the duplicated output is selected and the createTrack() request is refused by AudioFlinger as the selected output doesn't exist.
The notification is ignored by AudioFlinger because when it is sent by the terminating playback thread, the thread has already been removed from the playback thread list.

The fix consists in sending the notification in closeOutput() and not when exiting the playback thread.
The same fix is applied to record threads.
2009-09-15 07:10:12 -07:00
Eric Laurent
a6e58fe316 Fix issue 2115450: a2dp thread is started, even though we are only connected to headset and not playing music.
This is due to a regression introduced by change 24114: when no audio tracks are ready for mixing, 0s are written to audio hardware. However this should only happen if tracks have already been mixed since the audio flinger thread woke up.
Also do not write 0s to audio hardware in direct output threads when audio format is not linear PCM.
2009-09-14 02:37:15 -07:00
Eric Laurent
6ad8c64ce9 Fix issue 2107584: media server crash when AudioFlinger fails to allocate memory for track control block.
AudioFlinger: verify that mCblk is not null before using it in Track and RecordTrack contructors.
IAudioFlinger: check result of remote transaction before reading IAudioTrack and IAudioRecord.
IAudioTrack and IAudioRecord: check result of remote transaction before reading IMemory.
2009-09-09 05:16:08 -07:00
Eric Laurent
3522c80819 Fix issue 1992233: DTMF tones on Sholes is really long.
Add a parameter to ToneGenerator.startTone() allowing the caller to specify the tone duration. This is used by the phone application to have a precise control on the DTMF tone duration which was not possible with the use of delayed messaged.
Also modified AudioFlinger output threads so that 0s are written to the audio output stream when no more tracks are ready to mix instead of just sleeping. This avoids an issue where the end of a previous DTMF tone could stay in audio hardware buffers and be played just before the beginning of the next DTMF tone.
2009-09-08 22:56:07 -07:00