summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml59
-rw-r--r--include/media/ToneGenerator.h89
-rw-r--r--location/java/com/android/internal/location/GpsLocationProvider.java60
-rw-r--r--media/java/android/media/AudioManager.java77
-rw-r--r--media/java/android/media/AudioService.java176
-rw-r--r--media/java/android/media/ToneGenerator.java66
-rw-r--r--media/libmedia/ToneGenerator.cpp427
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java14
8 files changed, 804 insertions, 164 deletions
diff --git a/api/current.xml b/api/current.xml
index 2bab739d38d7..509abe1b782c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -63668,7 +63668,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="mode" type="int">
@@ -63879,7 +63879,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="mode" type="int">
@@ -68595,6 +68595,17 @@
visibility="public"
>
</field>
+<field name="TONE_SUP_CONFIRM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TONE_SUP_CONGESTION"
type="int"
transient="false"
@@ -68606,6 +68617,17 @@
visibility="public"
>
</field>
+<field name="TONE_SUP_CONGESTION_ABBREV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="31"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TONE_SUP_DIAL"
type="int"
transient="false"
@@ -68628,6 +68650,39 @@
visibility="public"
>
</field>
+<field name="TONE_SUP_INTERCEPT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="29"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_SUP_INTERCEPT_ABBREV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="30"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_SUP_PIP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TONE_SUP_RADIO_ACK"
type="int"
transient="false"
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index ec64e4d70434..6b0cc8ab8cce 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -18,7 +18,7 @@
#define ANDROID_TONEGENERATOR_H_
#include <utils/RefBase.h>
-#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -49,21 +49,30 @@ public:
TONE_DTMF_C, // C key: 1633Hz, 852Hz
TONE_DTMF_D, // D key: 1633Hz, 941Hz
// Call supervisory tones: 3GPP TS 22.001 (CEPT)
- TONE_SUP_DIAL, // Dial tone: 425Hz, continuous
- TONE_SUP_BUSY, // Busy tone: 425Hz, 500ms ON, 500ms OFF...
- TONE_SUP_CONGESTION, // Congestion tone: 425Hz, 200ms ON, 200ms OFF...
- TONE_SUP_RADIO_ACK, // Radio path acknowlegment: 425Hz, 200ms ON
+ TONE_SUP_DIAL, // Dial tone: CEPT: 425Hz, continuous
+ FIRST_SUP_TONE = TONE_SUP_DIAL,
+ TONE_SUP_BUSY, // Busy tone, CEPT: 425Hz, 500ms ON, 500ms OFF...
+ TONE_SUP_CONGESTION, // Congestion tone CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF...
+ TONE_SUP_RADIO_ACK, // Radio path acknowlegment, CEPT, ANSI: 425Hz, 200ms ON
TONE_SUP_RADIO_NOTAVAIL, // Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts
TONE_SUP_ERROR, // Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF...
- TONE_SUP_CALL_WAITING, // Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
- TONE_SUP_RINGTONE, // Ring Tone: 425Hz, 1s ON, 4s OFF...
+ TONE_SUP_CALL_WAITING, // Call Waiting CEPT,JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+ TONE_SUP_RINGTONE, // Ring Tone CEPT, JAPAN: 425Hz, 1s ON, 4s OFF...
+ LAST_SUP_TONE = TONE_SUP_RINGTONE,
// Proprietary tones: 3GPP TS 31.111
TONE_PROP_BEEP, // General beep: 400Hz+1200Hz, 35ms ON
TONE_PROP_ACK, // Positive Acknowlgement: 1200Hz, 100ms ON, 100ms OFF 2 bursts
- TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
+ TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
TONE_PROP_PROMPT, // Prompt tone: 400Hz+1200Hz, 200ms ON
TONE_PROP_BEEP2, // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on
- NUM_TONES
+ // Additional call supervisory tones: specified by IS-95 only
+ TONE_SUP_INTERCEPT, // Intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms.
+ TONE_SUP_INTERCEPT_ABBREV, // Abbreviated intercept: intercept tone limited to 4 seconds
+ TONE_SUP_CONGESTION_ABBREV, // Abbreviated congestion: congestion tone limited to 4 seconds
+ TONE_SUP_CONFIRM, // Confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle.
+ TONE_SUP_PIP, // Pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+ NUM_TONES,
+ NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
};
ToneGenerator(int streamType, float volume);
@@ -85,13 +94,45 @@ private:
TONE_RESTARTING //
};
- static const unsigned int TONEGEN_MAX_WAVES = 3;
- static const unsigned int TONEGEN_MAX_SEGMENTS = 4; // Maximun number of elenemts in
+
+ // Region specific tones.
+ // These supervisory tones are different depending on the region (USA/CANADA, JAPAN, rest of the world).
+ // When a tone in the range [FIRST_SUP_TONE, LAST_SUP_TONE] is requested, the region is determined
+ // from system property gsm.operator.iso-country and the proper tone descriptor is selected with the
+ // help of sToneMappingTable[]
+ enum regional_tone_type {
+ // ANSI supervisory tones
+ TONE_ANSI_DIAL = NUM_TONES, // Dial tone: a continuous 350 Hz + 440 Hz tone.
+ TONE_ANSI_BUSY, // Busy tone on: a 480 Hz + 620 Hz tone repeated in a 500 ms on, 500 ms off cycle.
+ TONE_ANSI_CONGESTION, // Network congestion (reorder) tone on: a 480 Hz + 620 Hz tone repeated in a 250 ms on, 250 ms off cycle.
+ TONE_ANSI_CALL_WAITING, // Call waiting tone on: 440 Hz, on for 300 ms, 9,7 s off followed by
+ // (440 Hz, on for 100 ms off for 100 ms, on for 100 ms, 9,7s off and repeated as necessary).
+ TONE_ANSI_RINGTONE, // Ring Tone: a 440 Hz + 480 Hz tone repeated in a 2 s on, 4 s off pattern.
+ // JAPAN Supervisory tones
+ TONE_JAPAN_DIAL, // Dial tone: 400Hz, continuous
+ TONE_JAPAN_BUSY, // Busy tone: 400Hz, 500ms ON, 500ms OFF...
+ TONE_JAPAN_RADIO_ACK, // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
+ NUM_ALTERNATE_TONES
+ };
+
+ enum region {
+ ANSI,
+ JAPAN,
+ CEPT,
+ NUM_REGIONS
+ };
+
+ static const unsigned char sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES];
+
+ static const unsigned int TONEGEN_MAX_WAVES = 3; // Maximun number of sine waves in a tone segment
+ static const unsigned int TONEGEN_MAX_SEGMENTS = 5; // Maximun number of segments in a tone descriptor
static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration
static const float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator().
// ToneDescriptor class contains all parameters needed to generate a tone:
- // - The array waveFreq[] contains the frequencies of all individual waves making the multi-tone.
+ // - The array waveFreq[]:
+ // 1 for static tone descriptors: contains the frequencies of all individual waves making the multi-tone.
+ // 2 for active tone descritors: contains the indexes of the WaveGenerator objects in mWaveGens
// The number of sine waves varies from 1 to TONEGEN_MAX_WAVES.
// The first null value indicates that no more waves are needed.
// - The array segments[] is used to generate the tone pulses. A segment is a period of time
@@ -100,17 +141,25 @@ private:
// The data stored in segments[] is the duration of the corresponding period in ms.
// The first segment encountered with a 0 duration indicates that no more segment follows.
// - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated.
- // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
- // If mCurCount > repeatCnt, the tone is stopped automatically.
+ // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
+ // If mCurCount > repeatCnt, the tone is stopped automatically. Otherwise, tone sequence will be
+ // restarted from segment repeatSegment.
+ // - repeatSegment number of the first repeated segment when repeatCnt is not null
- class ToneDescriptor {
+ class ToneSegment {
public:
+ unsigned int duration;
unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
- unsigned long segments[TONEGEN_MAX_SEGMENTS+1];
+ };
+
+ class ToneDescriptor {
+ public:
+ ToneSegment segments[TONEGEN_MAX_SEGMENTS+1];
unsigned long repeatCnt;
+ unsigned long repeatSegment;
};
- static const ToneDescriptor toneDescriptors[NUM_TONES];
+ static const ToneDescriptor sToneDescriptors[];
unsigned int mTotalSmp; // Total number of audio samples played (gives current time)
unsigned int mNextSegSmp; // Position of next segment transition expressed in samples
@@ -121,6 +170,7 @@ private:
unsigned short mCurSegment; // Current segment index in ToneDescriptor segments[]
unsigned short mCurCount; // Current sequence repeat count
volatile unsigned short mState; // ToneGenerator state (tone_state)
+ unsigned short mRegion;
const ToneDescriptor *mpToneDesc; // pointer to active tone descriptor
const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor
@@ -136,8 +186,9 @@ private:
bool initAudioTrack();
static void audioCallback(int event, void* user, void *info);
bool prepareWave();
- unsigned int numWaves();
+ unsigned int numWaves(unsigned int segmentIdx);
void clearWaveGens();
+ int getToneForRegion(int toneType);
// WaveGenerator generates a single sine wave
class WaveGenerator {
@@ -167,7 +218,7 @@ private:
short mAmplitude_Q15; // Q15 amplitude
};
- Vector<WaveGenerator *> mWaveGens; // list of active wave generators.
+ KeyedVector<unsigned short, WaveGenerator *> mWaveGens; // list of active wave generators.
};
}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 5877dd115899..97b6a620d302 100644
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -16,6 +16,8 @@
package com.android.internal.location;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -59,6 +61,9 @@ import java.util.Properties;
public class GpsLocationProvider extends ILocationProvider.Stub {
private static final String TAG = "GpsLocationProvider";
+
+ private static final boolean DEBUG = true;
+ private static final boolean VERBOSE = false;
/**
* Broadcast intent action indicating that the GPS has either been
@@ -151,6 +156,9 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// turn off GPS fix icon if we haven't received a fix in 10 seconds
private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
+
+ // number of fixes to receive before disabling GPS
+ private static final int MIN_FIX_COUNT = 10;
// true if we are enabled
private boolean mEnabled;
@@ -164,6 +172,9 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// requested frequency of fixes, in seconds
private int mFixInterval = 1;
+ // number of fixes we have received since we started navigating
+ private int mFixCount;
+
private int mPositionMode = GPS_POSITION_MODE_STANDALONE;
// true if we started navigation
@@ -196,6 +207,11 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private int mSuplDataConnectionState;
private final ConnectivityManager mConnMgr;
+ // Alarms
+ private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
+ private final AlarmManager mAlarmManager;
+ private final PendingIntent mWakeupIntent;
+
private final IBatteryStats mBatteryStats;
private final SparseIntArray mClientUids = new SparseIntArray();
@@ -257,11 +273,14 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
return mGpsStatusProvider;
}
- private class TelephonyBroadcastReceiver extends BroadcastReceiver {
+ private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+ if (action.equals(ALARM_WAKEUP)) {
+ if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
+ startNavigating();
+ } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
String state = intent.getStringExtra(Phone.STATE_KEY);
String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
@@ -278,7 +297,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
}
- }
+ };
public static boolean isSupported() {
return native_is_supported();
@@ -288,10 +307,13 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mContext = context;
mLocationManager = locationManager;
- TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver();
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
+
IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ALARM_WAKEUP);
intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- context.registerReceiver(receiver, intentFilter);
+ context.registerReceiver(mBroadcastReciever, intentFilter);
mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -512,11 +534,11 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
public void enableLocationTracking(boolean enable) {
if (enable) {
- mFixRequestTime = System.currentTimeMillis();
mTTFF = 0;
mLastFixTime = 0;
startNavigating();
} else {
+ mAlarmManager.cancel(mWakeupIntent);
stopNavigating();
}
}
@@ -622,7 +644,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
public void startNavigating() {
if (!mStarted) {
- if (Config.LOGV) Log.v(TAG, "startNavigating");
+ if (DEBUG) Log.d(TAG, "startNavigating");
mStarted = true;
if (!native_start(mPositionMode, false, mFixInterval)) {
mStarted = false;
@@ -631,11 +653,13 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// reset SV count to zero
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+ mFixCount = 0;
+ mFixRequestTime = System.currentTimeMillis();
}
}
public void stopNavigating() {
- if (Config.LOGV) Log.v(TAG, "stopNavigating");
+ if (DEBUG) Log.d(TAG, "stopNavigating");
if (mStarted) {
mStarted = false;
native_stop();
@@ -653,7 +677,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
*/
private void reportLocation(int flags, double latitude, double longitude, double altitude,
float speed, float bearing, float accuracy, long timestamp) {
- if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
+ if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
" timestamp: " + timestamp);
mLastFixTime = System.currentTimeMillis();
@@ -721,13 +745,23 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mContext.sendBroadcast(intent);
updateStatus(LocationProvider.AVAILABLE, mSvCount);
}
+
+ if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) {
+ if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT");
+ stopNavigating();
+ mFixCount = 0;
+ mAlarmManager.cancel(mWakeupIntent);
+ long now = SystemClock.elapsedRealtime();
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent);
+ }
}
/**
* called from native code to update our status
*/
private void reportStatus(int status) {
- if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status);
+ if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);
boolean wasNavigating = mNavigating;
mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
@@ -797,12 +831,12 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
- if (Config.LOGD) {
- if (Config.LOGV) Log.v(TAG, "SV count: " + svCount +
+ if (VERBOSE) {
+ Log.v(TAG, "SV count: " + svCount +
" ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
" almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
for (int i = 0; i < svCount; i++) {
- if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] +
+ Log.v(TAG, "sv: " + mSvs[i] +
" snr: " + (float)mSnrs[i]/10 +
" elev: " + mSvElevations[i] +
" azimuth: " + mSvAzimuths[i] +
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f509fb5abf26..e43c9c4386ea 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -642,7 +642,9 @@ public class AudioManager {
* <var>false</var> to turn it off
*/
public void setSpeakerphoneOn(boolean on){
- setRouting(MODE_IN_CALL, on ? ROUTE_SPEAKER : ROUTE_EARPIECE, ROUTE_ALL);
+ // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+ // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+ setRoutingP(MODE_INVALID, on ? ROUTE_SPEAKER: 0, ROUTE_SPEAKER);
}
/**
@@ -651,7 +653,7 @@ public class AudioManager {
* @return true if speakerphone is on, false if it's off
*/
public boolean isSpeakerphoneOn() {
- return (getRouting(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
+ return (getRoutingP(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
}
/**
@@ -661,14 +663,9 @@ public class AudioManager {
* headset; <var>false</var> to route audio to/from phone earpiece
*/
public void setBluetoothScoOn(boolean on){
- // Don't disable A2DP when turning off SCO.
- // A2DP does not affect in-call routing.
- setRouting(MODE_RINGTONE,
- on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_NORMAL,
- on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_IN_CALL,
- on ? ROUTE_BLUETOOTH_SCO: ROUTE_EARPIECE, ROUTE_ALL);
+ // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+ // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+ setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_SCO: 0, ROUTE_BLUETOOTH_SCO);
}
/**
@@ -678,7 +675,7 @@ public class AudioManager {
* false if otherwise
*/
public boolean isBluetoothScoOn() {
- return (getRouting(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
+ return (getRoutingP(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
}
/**
@@ -688,12 +685,9 @@ public class AudioManager {
* headset; <var>false</var> disable A2DP audio
*/
public void setBluetoothA2dpOn(boolean on){
- // the audio flinger chooses A2DP as a higher priority,
- // so there is no need to disable other routes.
- setRouting(MODE_RINGTONE,
- on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_NORMAL,
- on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
+ // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+ // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+ setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
}
/**
@@ -703,7 +697,7 @@ public class AudioManager {
* false if otherwise
*/
public boolean isBluetoothA2dpOn() {
- return (getRouting(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
+ return (getRoutingP(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
}
/**
@@ -714,14 +708,9 @@ public class AudioManager {
* @hide
*/
public void setWiredHeadsetOn(boolean on){
- // A2DP has higher priority than wired headset, so headset connect/disconnect events
- // should not affect A2DP routing
- setRouting(MODE_NORMAL,
- on ? ROUTE_HEADSET : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_RINGTONE,
- on ? ROUTE_HEADSET | ROUTE_SPEAKER : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_IN_CALL,
- on ? ROUTE_HEADSET : ROUTE_EARPIECE, ROUTE_ALL);
+ // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+ // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+ setRoutingP(MODE_INVALID, on ? ROUTE_HEADSET: 0, ROUTE_HEADSET);
}
/**
@@ -732,7 +721,7 @@ public class AudioManager {
* @hide
*/
public boolean isWiredHeadsetOn() {
- return (getRouting(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
+ return (getRoutingP(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
}
/**
@@ -860,7 +849,11 @@ public class AudioManager {
* more of ROUTE_xxx types. Set bits indicate that route should be on
* @param mask bit vector of routes to change, created from one or more of
* ROUTE_xxx types. Unset bits indicate the route should be left unchanged
+ *
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn(), setBluetoothA2dpOn() and setWiredHeadsetOn() methods instead.
*/
+
public void setRouting(int mode, int routes, int mask) {
IAudioService service = getService();
try {
@@ -876,7 +869,10 @@ public class AudioManager {
* @param mode audio mode to get route (e.g., MODE_RINGTONE)
* @return an audio route bit vector that can be compared with ROUTE_xxx
* bits
+ * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
+ * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
*/
+ @Deprecated
public int getRouting(int mode) {
IAudioService service = getService();
try {
@@ -1076,4 +1072,31 @@ public class AudioManager {
* {@hide}
*/
private IBinder mICallBack = new Binder();
+
+ /**
+ * {@hide}
+ */
+ private void setRoutingP(int mode, int routes, int mask) {
+ IAudioService service = getService();
+ try {
+ service.setRouting(mode, routes, mask);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setRouting", e);
+ }
+ }
+
+
+ /**
+ * {@hide}
+ */
+ private int getRoutingP(int mode) {
+ IAudioService service = getService();
+ try {
+ return service.getRouting(mode);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getRouting", e);
+ return -1;
+ }
+ }
+
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2e3e46014136..881de4d2a468 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -100,6 +100,10 @@ public class AudioService extends IAudioService.Stub {
private int[] mRoutes = new int[AudioSystem.NUM_MODES];
private Object mSettingsLock = new Object();
private boolean mMediaServerOk;
+ private boolean mSpeakerIsOn;
+ private boolean mBluetoothScoIsConnected;
+ private boolean mHeadsetIsConnected;
+ private boolean mBluetoothA2dpIsConnected;
private SoundPool mSoundPool;
private Object mSoundEffectsLock = new Object();
@@ -189,6 +193,10 @@ public class AudioService extends IAudioService.Stub {
mMediaServerOk = true;
AudioSystem.setErrorCallback(mAudioSystemCallback);
loadSoundEffects();
+ mSpeakerIsOn = false;
+ mBluetoothScoIsConnected = false;
+ mHeadsetIsConnected = false;
+ mBluetoothA2dpIsConnected = false;
}
private void createAudioSystemThread() {
@@ -606,8 +614,9 @@ public class AudioService extends IAudioService.Stub {
}
synchronized (mSettingsLock) {
if (mode != mMode) {
- AudioSystem.setMode(mode);
- mMode = mode;
+ if (AudioSystem.setMode(mode) == AudioSystem.AUDIO_STATUS_OK) {
+ mMode = mode;
+ }
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[streamType].mIndex;
@@ -623,18 +632,167 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#setRouting(int, int, int) */
public void setRouting(int mode, int routes, int mask) {
+ int incallMask = 0;
+ int ringtoneMask = 0;
+ int normalMask = 0;
+
if (!checkAudioSettingsPermission("setRouting()")) {
return;
}
synchronized (mSettingsLock) {
- if ((mRoutes[mode] & mask) != (routes & mask)) {
- AudioSystem.setRouting(mode, routes, mask);
- mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask);
+ // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+ // mode AudioSystem.MODE_INVALID is used only by the following AudioManager methods:
+ // setWiredHeadsetOn(), setBluetoothA2dpOn(), setBluetoothScoOn() and setSpeakerphoneOn().
+ // If applications are using AudioManager.setRouting() that is now deprecated, the routing
+ // command will be ignored.
+ if (mode == AudioSystem.MODE_INVALID) {
+ switch (mask) {
+ case AudioSystem.ROUTE_SPEAKER:
+ // handle setSpeakerphoneOn()
+ if (routes != 0 && !mSpeakerIsOn) {
+ mSpeakerIsOn = true;
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+ incallMask = AudioSystem.ROUTE_ALL;
+ } else if (mSpeakerIsOn) {
+ mSpeakerIsOn = false;
+ if (mBluetoothScoIsConnected) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
+ } else if (mHeadsetIsConnected) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+ } else {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+ }
+ incallMask = AudioSystem.ROUTE_ALL;
+ }
+ break;
+
+ case AudioSystem.ROUTE_BLUETOOTH_SCO:
+ // handle setBluetoothScoOn()
+ if (routes != 0 && !mBluetoothScoIsConnected) {
+ mBluetoothScoIsConnected = true;
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
+ mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_BLUETOOTH_SCO;
+ mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_BLUETOOTH_SCO;
+ incallMask = AudioSystem.ROUTE_ALL;
+ // A2DP has higher priority than SCO headset, so headset connect/disconnect events
+ // should not affect A2DP routing
+ ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ } else if (mBluetoothScoIsConnected) {
+ mBluetoothScoIsConnected = false;
+ if (mHeadsetIsConnected) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+ mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
+ mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_HEADSET;
+ } else {
+ if (mSpeakerIsOn) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+ } else {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+ }
+ mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_SPEAKER;
+ mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_SPEAKER;
+ }
+ incallMask = AudioSystem.ROUTE_ALL;
+ // A2DP has higher priority than SCO headset, so headset connect/disconnect events
+ // should not affect A2DP routing
+ ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ }
+ break;
+
+ case AudioSystem.ROUTE_HEADSET:
+ // handle setWiredHeadsetOn()
+ if (routes != 0 && !mHeadsetIsConnected) {
+ mHeadsetIsConnected = true;
+ // do not act upon headset connection if bluetooth SCO is connected to match phone app behavior
+ if (!mBluetoothScoIsConnected) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+ mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
+ mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_HEADSET;
+ incallMask = AudioSystem.ROUTE_ALL;
+ // A2DP has higher priority than wired headset, so headset connect/disconnect events
+ // should not affect A2DP routing
+ ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ }
+ } else if (mHeadsetIsConnected) {
+ mHeadsetIsConnected = false;
+ // do not act upon headset disconnection if bluetooth SCO is connected to match phone app behavior
+ if (!mBluetoothScoIsConnected) {
+ if (mSpeakerIsOn) {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+ } else {
+ mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+ }
+ mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_SPEAKER;
+ mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+ AudioSystem.ROUTE_SPEAKER;
+
+ incallMask = AudioSystem.ROUTE_ALL;
+ // A2DP has higher priority than wired headset, so headset connect/disconnect events
+ // should not affect A2DP routing
+ ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ }
+ }
+ break;
+
+ case AudioSystem.ROUTE_BLUETOOTH_A2DP:
+ // handle setBluetoothA2dpOn()
+ if (routes != 0 && !mBluetoothA2dpIsConnected) {
+ mBluetoothA2dpIsConnected = true;
+ mRoutes[AudioSystem.MODE_RINGTONE] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ mRoutes[AudioSystem.MODE_NORMAL] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ // the audio flinger chooses A2DP as a higher priority,
+ // so there is no need to disable other routes.
+ ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ } else if (mBluetoothA2dpIsConnected) {
+ mBluetoothA2dpIsConnected = false;
+ mRoutes[AudioSystem.MODE_RINGTONE] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ mRoutes[AudioSystem.MODE_NORMAL] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ // the audio flinger chooses A2DP as a higher priority,
+ // so there is no need to disable other routes.
+ ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ }
+ break;
+ }
+
+ // incallMask is != 0 means we must apply ne routing to MODE_IN_CALL mode
+ if (incallMask != 0) {
+ AudioSystem.setRouting(AudioSystem.MODE_IN_CALL,
+ mRoutes[AudioSystem.MODE_IN_CALL],
+ incallMask);
+ }
+ // ringtoneMask is != 0 means we must apply ne routing to MODE_RINGTONE mode
+ if (ringtoneMask != 0) {
+ AudioSystem.setRouting(AudioSystem.MODE_RINGTONE,
+ mRoutes[AudioSystem.MODE_RINGTONE],
+ ringtoneMask);
+ }
+ // normalMask is != 0 means we must apply ne routing to MODE_NORMAL mode
+ if (normalMask != 0) {
+ AudioSystem.setRouting(AudioSystem.MODE_NORMAL,
+ mRoutes[AudioSystem.MODE_NORMAL],
+ normalMask);
+ }
+
+ int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+ int index = mStreamStates[streamType].mIndex;
+ syncRingerAndNotificationStreamVolume(streamType, index, true);
+ setStreamVolumeInt(streamType, index, true);
}
- int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int index = mStreamStates[streamType].mIndex;
- syncRingerAndNotificationStreamVolume(streamType, index, true);
- setStreamVolumeInt(streamType, index, true);
}
}
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index 0901fbfced07..4b53756db118 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -130,25 +130,35 @@ public class ToneGenerator
*/
public static final int TONE_DTMF_D = 15;
/**
- * Call supervisory tone, Dial tone: 425Hz, continuous
- *
+ * Call supervisory tone, Dial tone:
+ * CEPT: 425Hz, continuous
+ * ANSI (IS-95): 350Hz+440Hz, continuous
+ * JAPAN: 400Hz, continuous
+ *
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_DIAL = 16;
/**
- * Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF...
- *
+ * Call supervisory tone, Busy:
+ * CEPT: 425Hz, 500ms ON, 500ms OFF...
+ * ANSI (IS-95): 480Hz+620Hz, 500ms ON, 500ms OFF...
+ * JAPAN: 400Hz, 500ms ON, 500ms OFF...
+ *
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_BUSY = 17;
/**
- * Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF...
+ * Call supervisory tone, Congestion:
+ * CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF...
+ * ANSI (IS-95): 480Hz+620Hz, 250ms ON, 250ms OFF...
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CONGESTION = 18;
/**
- * Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON
+ * Call supervisory tone, Radio path acknowlegment :
+ * CEPT, ANSI: 425Hz, 200ms ON
+ * JAPAN: 400Hz, 1s ON, 2s OFF...
*
* @see #ToneGenerator(int, int)
*/
@@ -166,13 +176,17 @@ public class ToneGenerator
*/
public static final int TONE_SUP_ERROR = 21;
/**
- * Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+ * Call supervisory tone, Call Waiting:
+ * CEPT, JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+ * ANSI (IS-95): 440 Hz, 300 ms ON, 9.7 s OFF, (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...)
*
* @see #ToneGenerator(int, int)
*/
public static final int TONE_SUP_CALL_WAITING = 22;
/**
- * Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF...
+ * Call supervisory tone, Ring Tone:
+ * CEPT, JAPAN: 425Hz, 1s ON, 4s OFF...
+ * ANSI (IS-95): 440Hz + 480Hz, 2s ON, 4s OFF...
*
* @see #ToneGenerator(int, int)
*/
@@ -207,6 +221,37 @@ public class ToneGenerator
* @see #ToneGenerator(int, int)
*/
public static final int TONE_PROP_BEEP2 = 28;
+ /**
+ * Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms
+ *
+ * @see #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUP_INTERCEPT = 29;
+ /**
+ * Call supervisory tone (IS-95), abbreviated intercept: intercept tone limited to 4 seconds
+ *
+ * @see #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUP_INTERCEPT_ABBREV = 30;
+ /**
+ * Call supervisory tone (IS-95), abbreviated congestion: congestion tone limited to 4 seconds
+ *
+ * @see #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUP_CONGESTION_ABBREV = 31;
+ /**
+ * Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle
+ *
+ * @see #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUP_CONFIRM = 32;
+ /**
+ * Call supervisory tone (IS-95), pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+ *
+ * @see #ToneGenerator(int, int)
+ */
+ public static final int TONE_SUP_PIP = 33;
+
/** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
@@ -258,6 +303,11 @@ public class ToneGenerator
* <li>{@link #TONE_PROP_NACK}
* <li>{@link #TONE_PROP_PROMPT}
* <li>{@link #TONE_PROP_BEEP2}
+ * <li>{@link #TONE_SUP_INTERCEPT}
+ * <li>{@link #TONE_SUP_INTERCEPT_ABBREV}
+ * <li>{@link #TONE_SUP_CONGESTION_ABBREV}
+ * <li>{@link #TONE_SUP_CONFIRM}
+ * <li>{@link #TONE_SUP_PIP}
* </ul>
* @see #ToneGenerator(int, int)
*/
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 856059328e4b..d1789addb922 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -24,44 +24,235 @@
#include <sys/resource.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include <cutils/properties.h>
#include "media/ToneGenerator.h"
+
namespace android {
+
// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
-const ToneGenerator::ToneDescriptor
- ToneGenerator::toneDescriptors[NUM_TONES] = {
- // waveFreq[] segments[] repeatCnt
- { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0
- { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1
- { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2
- { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3
- { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4
- { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5
- { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6
- { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7
- { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8
- { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9
- { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S
- { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P
- { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A
- { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B
- { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C
- { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D
- { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL
- { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY
- { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION
- { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK
- { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL
- { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
- { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
- { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
- { { 400, 1200, 0 }, { 40, 0 }, 0 }, // TONE_PROP_BEEP
- { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
- { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
- { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
- { { 400, 1200, 0 }, { 40, 200, 40, 0 }, 0 } // TONE_PROP_BEEP2
- };
+const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
+ { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_0
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_1
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_2
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_3
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_4
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_5
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_6
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_7
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_8
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_9
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_S
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_P
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_A
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_B
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_C
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_DTMF_D
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_DIAL
+ { segments: { { duration: 500 , waveFreq: { 425, 0 }},
+ { duration: 500, waveFreq: { 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_BUSY
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 200, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_CONGESTION
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_SUP_RADIO_ACK
+ { segments: { { duration: 200, waveFreq: { 425, 0 }},
+ { duration: 200, waveFreq: { 0 }},
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 2,
+ repeatSegment: 0 }, // TONE_SUP_RADIO_NOTAVAIL
+ { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }},
+ { duration: 1000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_ERROR
+ { segments: { { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 600, waveFreq: { 0 } },
+ { duration: 200, waveFreq: { 425, 0 } },
+ { duration: 3000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_CALL_WAITING
+ { segments: { { duration: 1000, waveFreq: { 425, 0 } },
+ { duration: 4000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_RINGTONE
+ { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_BEEP
+ { segments: { { duration: 100, waveFreq: { 1200, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 1,
+ repeatSegment: 0 }, // TONE_PROP_ACK
+ { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_NACK
+ { segments: { { duration: 200, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_PROMPT
+ { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 200, waveFreq: { 0 } },
+ { duration: 40, waveFreq: { 400, 1200, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 0,
+ repeatSegment: 0 }, // TONE_PROP_BEEP2
+ { segments: { { duration: 250, waveFreq: { 440, 0 } },
+ { duration: 250, waveFreq: { 620, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_SUP_INTERCEPT
+ { segments: { { duration: 250, waveFreq: { 440, 0 } },
+ { duration: 250, waveFreq: { 620, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 7,
+ repeatSegment: 0 }, // TONE_SUP_INTERCEPT_ABBREV
+ { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+ { duration: 250, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 7,
+ repeatSegment: 0 }, // TONE_SUP_CONGESTION_ABBREV
+ { segments: { { duration: 100, waveFreq: { 350, 440, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 2,
+ repeatSegment: 0 }, // TONE_SUP_CONFIRM
+ { segments: { { duration: 100, waveFreq: { 480, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: 3,
+ repeatSegment: 0 }, // TONE_SUP_PIP
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_DIAL
+ { segments: { { duration: 500, waveFreq: { 480, 620, 0 } },
+ { duration: 500, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_BUSY
+ { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+ { duration: 250, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_CONGESTION
+ { segments: { { duration: 300, waveFreq: { 440, 0 } },
+ { duration: 9700, waveFreq: { 0 } },
+ { duration: 100, waveFreq: { 440, 0 } },
+ { duration: 100, waveFreq: { 0 } },
+ { duration: 100, waveFreq: { 440, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 1 }, // TONE_ANSI_CALL_WAITING
+ { segments: { { duration: 2000, waveFreq: { 440, 480, 0 } },
+ { duration: 4000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_ANSI_RINGTONE
+ { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_DIAL
+ { segments: { { duration: 500, waveFreq: { 400, 0 } },
+ { duration: 500, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_BUSY
+ { segments: { { duration: 1000, waveFreq: { 400, 0 } },
+ { duration: 2000, waveFreq: { 0 } },
+ { duration: 0 , waveFreq: { 0 }}},
+ repeatCnt: ToneGenerator::TONEGEN_INF,
+ repeatSegment: 0 }, // TONE_JAPAN_RADIO_ACK
+};
+
+// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
+// to actual tone for current region.
+const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
+ { // ANSI
+ TONE_ANSI_DIAL, // TONE_SUP_DIAL
+ TONE_ANSI_BUSY, // TONE_SUP_BUSY
+ TONE_ANSI_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_ANSI_CALL_WAITING, // TONE_SUP_CALL_WAITING
+ TONE_ANSI_RINGTONE // TONE_SUP_RINGTONE
+ },
+ { // JAPAN
+ TONE_JAPAN_DIAL, // TONE_SUP_DIAL
+ TONE_JAPAN_BUSY, // TONE_SUP_BUSY
+ TONE_SUP_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_JAPAN_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING
+ TONE_SUP_RINGTONE // TONE_SUP_RINGTONE
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
// ToneGenerator class Implementation
@@ -105,6 +296,17 @@ ToneGenerator::ToneGenerator(int streamType, float volume) {
// Generate tone by chunks of 20 ms to keep cadencing precision
mProcessSize = (mSamplingRate * 20) / 1000;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("gsm.operator.iso-country", value, "");
+ if (strcmp(value,"us") == 0 ||
+ strcmp(value,"ca") == 0) {
+ mRegion = ANSI;
+ } else if (strcmp(value,"jp") == 0) {
+ mRegion = JAPAN;
+ } else {
+ mRegion = CEPT;
+ }
+
if (initAudioTrack()) {
LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
} else {
@@ -170,7 +372,8 @@ bool ToneGenerator::startTone(int toneType) {
mLock.lock();
// Get descriptor for requested tone
- mpNewToneDesc = &toneDescriptors[toneType];
+ toneType = getToneForRegion(toneType);
+ mpNewToneDesc = &sToneDescriptors[toneType];
if (mState == TONE_INIT) {
if (prepareWave()) {
@@ -333,6 +536,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
short *lpOut = buffer->i16;
unsigned int lNumSmp = buffer->size/sizeof(short);
+ const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
if (buffer->size == 0) return;
@@ -377,7 +581,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
// Exit if tone sequence is over
- if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
if (lpToneGen->mState == TONE_PLAYING) {
lpToneGen->mState = TONE_STOPPING;
}
@@ -390,52 +594,64 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
lGenSmp = lReqSmp;
-
- if (lpToneGen->mCurSegment & 0x0001) {
- // If odd segment, OFF -> ON transition : reset wave generator
- lWaveCmd = WaveGenerator::WAVEGEN_START;
-
- LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
- } else {
- // If even segment, ON -> OFF transition : ramp volume down
+
+ // If segment, ON -> OFF transition : ramp volume down
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
lWaveCmd = WaveGenerator::WAVEGEN_STOP;
-
+ unsigned int lFreqIdx = 0;
+ unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
+
+ while (lFrequency != 0) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
+ lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
+ }
LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
}
-
- // Pre increment segment index and handle loop if last segment reached
- if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+
+ // Go to next segment
+ lpToneGen->mCurSegment++;
+
+ // Handle loop if last segment reached
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
// Pre increment loop count and restart if total count not reached. Stop sequence otherwise
- if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+ if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
- lpToneGen->mCurSegment = 0;
+ lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
+ if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+ }
LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
} else {
+ lGenSmp = 0;
LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
-
- // Cancel OFF->ON transition in case previous segment tone state was OFF
- if (!(lpToneGen->mCurSegment & 0x0001)) {
- lGenSmp = 0;
- }
}
} else {
LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
(lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
+ // If next segment is not silent, OFF -> ON transition : reset wave generator
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+ LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ } else {
+ lGenSmp = 0;
+ }
}
// Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
lpToneGen->mNextSegSmp
- += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+ += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
} else {
// Inside a segment keep tone ON or OFF
- if (lpToneGen->mCurSegment & 0x0001) {
+ if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
lGenSmp = 0; // If odd segment, tone is currently OFF
} else {
lGenSmp = lReqSmp; // If event segment, tone is currently ON
@@ -444,11 +660,13 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
if (lGenSmp) {
// If samples must be generated, call all active wave generators and acumulate waves in lpOut
- unsigned int lWaveIdx;
+ unsigned int lFreqIdx = 0;
+ unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
- for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
- WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+ while (lFrequency != 0) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
}
}
@@ -501,7 +719,7 @@ audioCallback_EndLoop:
// Method: ToneGenerator::prepareWave()
//
// Description: Prepare wave generators and reset tone sequencer state machine.
-// mpNewToneDesc must have been initialized befoire calling this function.
+// mpNewToneDesc must have been initialized before calling this function.
// Input:
// none
//
@@ -510,40 +728,48 @@ audioCallback_EndLoop:
//
////////////////////////////////////////////////////////////////////////////////
bool ToneGenerator::prepareWave() {
- unsigned int lCnt = 0;
- unsigned int lNumWaves;
+ unsigned int segmentIdx = 0;
if (!mpNewToneDesc) {
return false;
}
+
// Remove existing wave generators if any
clearWaveGens();
mpToneDesc = mpNewToneDesc;
- // Get total number of sine waves: needed to adapt sine wave gain.
- lNumWaves = numWaves();
-
- // Instantiate as many wave generators as listed in descriptor
- while (lCnt < lNumWaves) {
- ToneGenerator::WaveGenerator *lpWaveGen =
- new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
- mpToneDesc->waveFreq[lCnt],
- TONEGEN_GAIN/lNumWaves);
- if (lpWaveGen == 0) {
- goto prepareWave_exit;
+ while (mpToneDesc->segments[segmentIdx].duration) {
+ // Get total number of sine waves: needed to adapt sine wave gain.
+ unsigned int lNumWaves = numWaves(segmentIdx);
+ unsigned int freqIdx = 0;
+ unsigned int frequency = mpToneDesc->segments[segmentIdx].waveFreq[freqIdx];
+ while (frequency) {
+ // Instantiate a wave generator if ot already done for this frequency
+ if (mWaveGens.indexOfKey(frequency) == NAME_NOT_FOUND) {
+ ToneGenerator::WaveGenerator *lpWaveGen =
+ new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+ frequency,
+ TONEGEN_GAIN/lNumWaves);
+ if (lpWaveGen == 0) {
+ goto prepareWave_exit;
+ }
+ mWaveGens.add(frequency, lpWaveGen);
+ }
+ frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx];
}
-
- mWaveGens.push(lpWaveGen);
- LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
- lCnt++;
+ segmentIdx++;
}
// Initialize tone sequencer
mTotalSmp = 0;
mCurSegment = 0;
mCurCount = 0;
- mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+ if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
+ mNextSegSmp = TONEGEN_INF;
+ } else{
+ mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
+ }
return true;
@@ -559,19 +785,22 @@ prepareWave_exit:
//
// Method: ToneGenerator::numWaves()
//
-// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+// Description: Count number of sine waves needed to generate a tone segment (e.g 2 for DTMF).
//
// Input:
-// none
+// segmentIdx tone segment index
//
// Output:
// returned value: nummber of sine waves
//
////////////////////////////////////////////////////////////////////////////////
-unsigned int ToneGenerator::numWaves() {
+unsigned int ToneGenerator::numWaves(unsigned int segmentIdx) {
unsigned int lCnt = 0;
- while (mpToneDesc->waveFreq[lCnt]) {
+ if (mpToneDesc->segments[segmentIdx].duration) {
+ while (mpToneDesc->segments[segmentIdx].waveFreq[lCnt]) {
+ lCnt++;
+ }
lCnt++;
}
@@ -595,10 +824,38 @@ unsigned int ToneGenerator::numWaves() {
void ToneGenerator::clearWaveGens() {
LOGV("Clearing mWaveGens:");
- while (!mWaveGens.isEmpty()) {
- delete mWaveGens.top();
- mWaveGens.pop();
+ for (size_t lIdx = 0; lIdx < mWaveGens.size(); lIdx++) {
+ delete mWaveGens.valueAt(lIdx);
}
+ mWaveGens.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::getToneForRegion()
+//
+// Description: Get correct ringtone type according to current region.
+// The corrected ring tone type is the tone descriptor index in sToneDescriptors[].
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+int ToneGenerator::getToneForRegion(int toneType) {
+ int regionTone;
+
+ if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) {
+ regionTone = toneType;
+ } else {
+ regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
+ }
+
+ LOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone);
+
+ return regionTone;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
index da18e74f5ca4..c75b96b8746f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
@@ -74,7 +74,19 @@ import android.media.AudioManager;
break;
}
}
-
+
+ for (type = ToneGenerator.TONE_SUP_INTERCEPT;
+ type <= ToneGenerator.TONE_SUP_PIP; type++) {
+ if (toneGen.startTone(type)) {
+ Thread.sleep(5000);
+ toneGen.stopTone();
+ Thread.sleep(200);
+ } else {
+ result = false;
+ break;
+ }
+ }
+
toneGen.release();
return result;
}