2013-02-20 114 views
22

我用下面的代碼來啓動語音識別安卓使用Android RecognizerIntent與藍牙耳機

PackageManager pm = getPackageManager(); 
List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); 

if (activities.size() == 0) { 
    displayWarning("This device does not support speech recognition"); 
    return; 
} 

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 

startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE); 

這工作得很好。但是,它似乎不接受來自使用「手機音頻」配置文件配對和連接的藍牙耳機的語音輸入。

我可以使用名爲SoundAbout的應用程序強制「媒體音頻」爲「藍牙(單聲道)(SCO)」。有了這個應用程序集,我的語音識別現在可以從我的耳機接收我的語音輸入。

如何使用RecognizerIntent並從藍牙耳機獲取語音輸入?

我在API級別16中看到有一個新的意圖操作ACTION_VOICE_SEARCH_HANDS_FREE。這對我來說太新了,但這會解決我的問題嗎?

我是否必須在AudioManager(如我假設SoundAbout所做的)中使用setBluetoothScoOn()或startBluetoothSco()來路由音頻輸入?

回答

42

清單許可

<uses-permission android:name="android.permission.BLUETOOTH" /> 
<uses-permission android:name="android.permission.BROADCAST_STICKY" /> 
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> 

ActivityService創建內部類BluetoothHelper extends BluetoothHeadSetUtils。聲明一個類成員mBluetoothHelperonCreate()

BluetoothHelper mBluetoothHelper; 

@Override 
public void onCreate() 
{ 
    mBluetoothHelper = new BluetoothHelper(this); 
} 

@Override 
onResume() 
{ 
    mBluetoothHelper.start(); 
} 

@Override 
onPause() 
{ 
    mBluetoothHelper.stop(); 
} 

// inner class 
// BluetoothHeadsetUtils is an abstract class that has 
// 4 abstracts methods that need to be implemented. 
private class BluetoothHelper extends BluetoothHeadSetUtils 
{ 
    public BluetoothHelper(Context context) 
    { 
     super(context); 
    } 

    @Override 
    public void onScoAudioDisconnected() 
    { 
     // Cancel speech recognizer if desired 
    } 

    @Override 
    public void onScoAudioConnected() 
    {   
     // Should start speech recognition here if not already started 
    } 

    @Override 
    public void onHeadsetDisconnected() 
    { 

    } 

    @Override 
    public void onHeadsetConnected() 
    { 

    } 
} 

處理文本使用藍牙耳機語音實例化它,你需要設置AudioManager打電話說話之前STREAM_VOICE_CALL。或使用下面的代碼

protected void speak(String text) 
{ 

    HashMap<String, String> myHashRender = new HashMap<String, String>(); 

    if (mBluetoothHelper.isOnHeadsetSco()) 
    { 
     myHashRender.put(TextToSpeech.Engine.KEY_PARAM_STREAM, 
      String.valueOf(AudioManager.STREAM_VOICE_CALL)); 
    } 
    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, myHashRender); 
} 

將BluetoothHeadsetUtils類複製到您的項目中。

import java.util.List; 

import android.annotation.SuppressLint; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothClass; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothHeadset; 
import android.bluetooth.BluetoothProfile; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.media.AudioManager; 
import android.os.Build; 
import android.os.CountDownTimer; 
import android.util.Log; 

/** 
* This is a utility to detect bluetooth headset connection and establish audio connection 
* for android API >= 8. This includes a work around for API < 11 to detect already connected headset 
* before the application starts. This work around would only fails if Sco audio 
* connection is accepted but the connected device is not a headset. 
* 
* @author Hoan Nguyen 
* 
*/ 
public abstract class BluetoothHeadsetUtils 
{ 
    private Context mContext; 

    private BluetoothAdapter mBluetoothAdapter; 
    private BluetoothHeadset mBluetoothHeadset; 
    private BluetoothDevice mConnectedHeadset; 

    private AudioManager mAudioManager; 

    private boolean mIsCountDownOn; 
    private boolean mIsStarting; 
    private boolean mIsOnHeadsetSco; 
    private boolean mIsStarted; 

    private static final String TAG = "BluetoothHeadsetUtils"; //$NON-NLS-1$ 

    /** 
    * Constructor 
    * @param context 
    */ 
    public BluetoothHeadsetUtils(Context context) 
    { 
     mContext = context; 
     mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
     mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 
    } 

    /** 
    * Call this to start BluetoothHeadsetUtils functionalities. 
    * @return The return value of startBluetooth() or startBluetooth11() 
    */ 
    public boolean start() 
    { 
     if (!mIsStarted) 
     { 
      mIsStarted = true; 

      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) 
      { 
       mIsStarted = startBluetooth(); 
      } 
      else 
      { 
       mIsStarted = startBluetooth11(); 
      } 
     } 

     return mIsStarted; 
    } 

    /** 
    * Should call this on onResume or onDestroy. 
    * Unregister broadcast receivers and stop Sco audio connection 
    * and cancel count down. 
    */ 
    public void stop() 
    { 
     if (mIsStarted) 
     { 
      mIsStarted = false; 

      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) 
      { 
       stopBluetooth(); 
      } 
      else 
      { 
       stopBluetooth11(); 
      } 
     } 
    } 

    /** 
    * 
    * @return true if audio is connected through headset. 
    */ 
    public boolean isOnHeadsetSco() 
    { 
     return mIsOnHeadsetSco; 
    } 

    public abstract void onHeadsetDisconnected(); 

    public abstract void onHeadsetConnected(); 

    public abstract void onScoAudioDisconnected(); 

    public abstract void onScoAudioConnected(); 

    /** 
    * Register for bluetooth headset connection states and Sco audio states. 
    * Try to connect to bluetooth headset audio by calling startBluetoothSco(). 
    * This is a work around for API < 11 to detect if a headset is connected before 
    * the application starts. 
    * 
    * The official documentation for startBluetoothSco() states 
    * 
    * "This method can be used by applications wanting to send and received audio to/from 
    * a bluetooth SCO headset while the phone is not in call." 
    * 
    * Does this mean that startBluetoothSco() would fail if the connected bluetooth device 
    * is not a headset? 
    * 
    * Thus if a call to startBluetoothSco() is successful, i.e mBroadcastReceiver will receive 
    * an ACTION_SCO_AUDIO_STATE_CHANGED with intent extra SCO_AUDIO_STATE_CONNECTED, then 
    * we assume that a headset is connected. 
    * 
    * @return false if device does not support bluetooth or current platform does not supports 
    *    use of SCO for off call. 
    */ 
    @SuppressWarnings("deprecation") 
    private boolean startBluetooth() 
    { 
     Log.d(TAG, "startBluetooth"); //$NON-NLS-1$ 

     // Device support bluetooth 
     if (mBluetoothAdapter != null) 
     {  
      if (mAudioManager.isBluetoothScoAvailableOffCall()) 
      { 
       mContext.registerReceiver(mBroadcastReceiver, 
             new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); 
       mContext.registerReceiver(mBroadcastReceiver, 
             new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)); 
       mContext.registerReceiver(mBroadcastReceiver, 
             new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)); 

       // Need to set audio mode to MODE_IN_CALL for call to startBluetoothSco() to succeed. 
       mAudioManager.setMode(AudioManager.MODE_IN_CALL); 

       mIsCountDownOn = true; 
       // mCountDown repeatedly tries to start bluetooth Sco audio connection. 
       mCountDown.start(); 

       // need for audio sco, see mBroadcastReceiver 
       mIsStarting = true; 

       return true; 
      } 
     } 

     return false; 
    } 

    /** 
    * Register a headset profile listener 
    * @return false if device does not support bluetooth or current platform does not supports 
    *     use of SCO for off call or error in getting profile proxy. 
    */ 
    @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
    private boolean startBluetooth11() 
    { 
     Log.d(TAG, "startBluetooth11"); //$NON-NLS-1$ 

     // Device support bluetooth 
     if (mBluetoothAdapter != null) 
     { 
      if (mAudioManager.isBluetoothScoAvailableOffCall()) 
      { 
       // All the detection and audio connection are done in mHeadsetProfileListener 
       if (mBluetoothAdapter.getProfileProxy(mContext, 
                mHeadsetProfileListener, 
                BluetoothProfile.HEADSET)) 
       { 
        return true; 
       } 
      } 
     } 

     return false; 
    } 

    /** 
    * API < 11 
    * Unregister broadcast receivers and stop Sco audio connection 
    * and cancel count down. 
    */ 
    private void stopBluetooth() 
    { 
     Log.d(TAG, "stopBluetooth"); //$NON-NLS-1$ 

     if (mIsCountDownOn) 
     { 
      mIsCountDownOn = false; 
      mCountDown.cancel(); 
     } 

     // Need to stop Sco audio connection here when the app 
     // change orientation or close with headset still turns on. 
     mContext.unregisterReceiver(mBroadcastReceiver); 
     mAudioManager.stopBluetoothSco(); 
     mAudioManager.setMode(AudioManager.MODE_NORMAL); 
    } 

    /** 
    * API >= 11 
    * Unregister broadcast receivers and stop Sco audio connection 
    * and cancel count down. 
    */ 
    @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
    protected void stopBluetooth11() 
    { 
     Log.d(TAG, "stopBluetooth11"); //$NON-NLS-1$ 

     if (mIsCountDownOn) 
     { 
      mIsCountDownOn = false; 
      mCountDown11.cancel(); 
     } 

     if (mBluetoothHeadset != null) 
     { 
      // Need to call stopVoiceRecognition here when the app 
      // change orientation or close with headset still turns on. 
      mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset); 
      mContext.unregisterReceiver(mHeadsetBroadcastReceiver); 
      mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); 
      mBluetoothHeadset = null; 
     } 
    } 

    /** 
    * Broadcast receiver for API < 11 
    * Handle headset and Sco audio connection states. 
    */ 
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() 
    { 
     @SuppressWarnings({"deprecation", "synthetic-access"}) 
     @Override 
     public void onReceive(Context context, Intent intent) 
     { 
      String action = intent.getAction(); 

      if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) 
      {  
       mConnectedHeadset = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 
       BluetoothClass bluetoothClass = mConnectedHeadset.getBluetoothClass(); 
       if (bluetoothClass != null) 
       { 
        // Check if device is a headset. Besides the 2 below, are there other 
        // device classes also qualified as headset? 
        int deviceClass = bluetoothClass.getDeviceClass(); 
        if (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE 
         || deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) 
        { 
         // start bluetooth Sco audio connection. 
         // Calling startBluetoothSco() always returns faIL here, 
         // that why a count down timer is implemented to call 
         // startBluetoothSco() in the onTick. 
         mAudioManager.setMode(AudioManager.MODE_IN_CALL); 
         mIsCountDownOn = true; 
         mCountDown.start(); 

         // override this if you want to do other thing when the device is connected. 
         onHeadsetConnected(); 
        } 
       } 

       Log.d(TAG, mConnectedHeadset.getName() + " connected"); //$NON-NLS-1$ 
      } 
      else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) 
      { 
       Log.d(TAG, "Headset disconnected"); //$NON-NLS-1$ 

       if (mIsCountDownOn) 
       { 
        mIsCountDownOn = false; 
        mCountDown.cancel(); 
       } 

       mAudioManager.setMode(AudioManager.MODE_NORMAL); 

       // override this if you want to do other thing when the device is disconnected. 
       onHeadsetDisconnected(); 
      } 
      else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)) 
      { 
       int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 
               AudioManager.SCO_AUDIO_STATE_ERROR); 

       if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) 
       { 
        mIsOnHeadsetSco = true; 

        if (mIsStarting) 
        { 
         // When the device is connected before the application starts, 
         // ACTION_ACL_CONNECTED will not be received, so call onHeadsetConnected here 
         mIsStarting = false; 
         onHeadsetConnected(); 
        } 

        if (mIsCountDownOn) 
        { 
         mIsCountDownOn = false; 
         mCountDown.cancel(); 
        } 

        // override this if you want to do other thing when Sco audio is connected. 
        onScoAudioConnected(); 

        Log.d(TAG, "Sco connected"); //$NON-NLS-1$ 
       } 
       else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) 
       { 
        Log.d(TAG, "Sco disconnected"); //$NON-NLS-1$ 

        // Always receive SCO_AUDIO_STATE_DISCONNECTED on call to startBluetooth() 
        // which at that stage we do not want to do anything. Thus the if condition. 
        if (!mIsStarting) 
        { 
         mIsOnHeadsetSco = false; 

         // Need to call stopBluetoothSco(), otherwise startBluetoothSco() 
         // will not be successful. 
         mAudioManager.stopBluetoothSco(); 

         // override this if you want to do other thing when Sco audio is disconnected. 
         onScoAudioDisconnected(); 
        } 
       } 
      } 
     } 
    }; 

    /** 
    * API < 11 
    * Try to connect to audio headset in onTick. 
    */ 
    private CountDownTimer mCountDown = new CountDownTimer(10000, 1000) 
    { 

     @SuppressWarnings("synthetic-access") 
     @Override 
     public void onTick(long millisUntilFinished) 
     { 
      // When this call is successful, this count down timer will be canceled. 
      mAudioManager.startBluetoothSco(); 

      Log.d(TAG, "\nonTick start bluetooth Sco"); //$NON-NLS-1$ 
     } 

     @SuppressWarnings("synthetic-access") 
     @Override 
     public void onFinish() 
     { 
      // Calls to startBluetoothSco() in onStick are not successful. 
      // Should implement something to inform user of this failure 
      mIsCountDownOn = false; 
      mAudioManager.setMode(AudioManager.MODE_NORMAL); 

      Log.d(TAG, "\nonFinish fail to connect to headset audio"); //$NON-NLS-1$ 
     } 
    }; 

    /** 
    * API >= 11 
    * Check for already connected headset and if so start audio connection. 
    * Register for broadcast of headset and Sco audio connection states. 
    */ 
    private BluetoothProfile.ServiceListener mHeadsetProfileListener = new BluetoothProfile.ServiceListener() 
    { 

     /** 
     * This method is never called, even when we closeProfileProxy on onPause. 
     * When or will it ever be called??? 
     */ 
     @Override 
     public void onServiceDisconnected(int profile) 
     { 
      Log.d(TAG, "Profile listener onServiceDisconnected"); //$NON-NLS-1$ 
      stopBluetooth11(); 
     } 

     @SuppressWarnings("synthetic-access") 
     @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
     @Override 
     public void onServiceConnected(int profile, BluetoothProfile proxy) 
     { 
      Log.d(TAG, "Profile listener onServiceConnected"); //$NON-NLS-1$ 

      // mBluetoothHeadset is just a headset profile, 
      // it does not represent a headset device. 
      mBluetoothHeadset = (BluetoothHeadset) proxy; 

      // If a headset is connected before this application starts, 
      // ACTION_CONNECTION_STATE_CHANGED will not be broadcast. 
      // So we need to check for already connected headset. 
      List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices(); 
      if (devices.size() > 0) 
      { 
       // Only one headset can be connected at a time, 
       // so the connected headset is at index 0. 
       mConnectedHeadset = devices.get(0); 

       onHeadsetConnected(); 

       // Should not need count down timer, but just in case. 
       // See comment below in mHeadsetBroadcastReceiver onReceive() 
       mIsCountDownOn = true; 
       mCountDown11.start(); 

       Log.d(TAG, "Start count down"); //$NON-NLS-1$ 
      } 

      // During the active life time of the app, a user may turn on and off the headset. 
      // So register for broadcast of connection states. 
      mContext.registerReceiver(mHeadsetBroadcastReceiver, 
          new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)); 
      // Calling startVoiceRecognition does not result in immediate audio connection. 
      // So register for broadcast of audio connection states. This broadcast will 
      // only be sent if startVoiceRecognition returns true. 
      mContext.registerReceiver(mHeadsetBroadcastReceiver, 
          new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)); 
     } 
    }; 

    /** 
    * API >= 11 
    * Handle headset and Sco audio connection states. 
    */ 
    private BroadcastReceiver mHeadsetBroadcastReceiver = new BroadcastReceiver() 
    { 

     @SuppressWarnings("synthetic-access") 
     @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
     @Override 
     public void onReceive(Context context, Intent intent) 
     { 
      String action = intent.getAction(); 
      int state; 
      if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) 
      { 
       state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 
              BluetoothHeadset.STATE_DISCONNECTED); 
       Log.d(TAG, "\nAction = " + action + "\nState = " + state); //$NON-NLS-1$ //$NON-NLS-2$ 
       if (state == BluetoothHeadset.STATE_CONNECTED) 
       { 
        mConnectedHeadset = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 

        // Calling startVoiceRecognition always returns false here, 
        // that why a count down timer is implemented to call 
        // startVoiceRecognition in the onTick. 
        mIsCountDownOn = true; 
        mCountDown11.start(); 

        // override this if you want to do other thing when the device is connected. 
        onHeadsetConnected(); 

        Log.d(TAG, "Start count down"); //$NON-NLS-1$ 
       } 
       else if (state == BluetoothHeadset.STATE_DISCONNECTED) 
       { 
        // Calling stopVoiceRecognition always returns false here 
        // as it should since the headset is no longer connected. 
        if (mIsCountDownOn) 
        { 
         mIsCountDownOn = false; 
         mCountDown11.cancel(); 
        } 
        mConnectedHeadset = null; 

        // override this if you want to do other thing when the device is disconnected. 
        onHeadsetDisconnected(); 

        Log.d(TAG, "Headset disconnected"); //$NON-NLS-1$ 
       } 
      } 
      else // audio 
      { 
       state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 
       Log.d(TAG, "\nAction = " + action + "\nState = " + state); //$NON-NLS-1$ //$NON-NLS-2$ 
       if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) 
       { 
        Log.d(TAG, "\nHeadset audio connected"); //$NON-NLS-1$ 

        mIsOnHeadsetSco = true; 

        if (mIsCountDownOn) 
        { 
         mIsCountDownOn = false; 
         mCountDown11.cancel(); 
        } 

        // override this if you want to do other thing when headset audio is connected. 
        onScoAudioConnected(); 
       } 
       else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) 
       { 
        mIsOnHeadsetSco = false; 

        // The headset audio is disconnected, but calling 
        // stopVoiceRecognition always returns true here. 
        mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset); 

        // override this if you want to do other thing when headset audio is disconnected. 
        onScoAudioDisconnected(); 

        Log.d(TAG, "Headset audio disconnected"); //$NON-NLS-1$ 
       } 
      } 
     } 
    }; 

    /** 
    * API >= 11 
    * Try to connect to audio headset in onTick. 
    */ 
    private CountDownTimer mCountDown11 = new CountDownTimer(10000, 1000) 
    { 
     @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
     @SuppressWarnings("synthetic-access") 
     @Override 
     public void onTick(long millisUntilFinished) 
     { 
      // First stick calls always returns false. The second stick 
      // always returns true if the countDownInterval is set to 1000. 
      // It is somewhere in between 500 to a 1000. 
      mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset); 

      Log.d(TAG, "onTick startVoiceRecognition"); //$NON-NLS-1$ 
     } 

     @SuppressWarnings("synthetic-access") 
     @Override 
     public void onFinish() 
     { 
      // Calls to startVoiceRecognition in onStick are not successful. 
      // Should implement something to inform user of this failure 
      mIsCountDownOn = false; 
      Log.d(TAG, "\nonFinish fail to connect to headset audio"); //$NON-NLS-1$ 
     } 
    }; 

} 

(2013年4月30)編輯以在必要時切換到@TargetApi(Build.VERSION_CODES.HONEYCOMB)。如果您對API 8或9的java.lang.NoClassDefFoundError有問題,請刪除所有API> = 11代碼。 startBluetoothSco()適用於所有API版本。

+0

感謝您的詳細解答。這是一個演示,我們決定在這一點上我們不需要耳機,所以我沒有得到測試。但是,這個答案中有這麼多細節我相信它會有幫助。 – 2013-03-13 12:43:29

+0

使BluetoothHeadsetUtils在start()方法中抽象並修復一個輕微的錯誤。 – 2013-03-29 19:49:21

+0

如何觸發else if(action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)) – senzacionale 2013-07-16 21:30:15

2

儘管藍牙耳機已配對並連接到電話音頻配置文件(HF/HS),但實際的音頻連接(SCO)僅在來電和接受呼叫時才建立。

爲了您的VR應用程序接受來自藍牙耳機語音輸入您的應用程序將不得不建立一個SCO對一些VR輸入觸發耳機, 您將需要使用以下 - isBluetoothScoAvailableOffCall檢查平臺支持此功能,然後使用 startBluetoothSco和stopBluetoothSco啓動SCO到耳機。

+0

感謝。我已經用startBluetoothSco方法解決了我的問題,但這隻適用於VR,而不適用於TTS。還有另一種方法可以讓TTS對着耳機說話嗎? – 2013-03-28 22:37:41

1

startBluetoothSco需要很長時間才能建立,如果您需要將其用於語音控制,這是個問題。

有沒有一個快速的方法來使用藍牙麥克風聽,然後在聽後關閉它?

如果連接是在整個時間,那麼不可能通過A2DP流式傳輸音頻。

所以,理想的世界:

音頻輸出A2DP通過。當它開始聆聽時,它使用SCO藍牙麥克風。任何迴應都是A2DP。

事實上,如果它已經連接 - 你可以通過改變媒體流來調用流來切換?如果是這樣,是否有明顯的延遲?

9

我認爲你所要做的就是改變你的應用程序的音頻設置。

當您想要通過藍牙從耳機接收和發送聲音時,您應該輸入以下代碼。

AudioManager audioManager; 

audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); 

audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); 
audioManager.startBluetoothSco(); 
audioManager.setBluetoothScoOn(true); 

當您不使用藍牙時,請不要忘記在以下方法中恢復手機的正常設置。

audioManager.setMode(AudioManager.MODE_NORMAL); 
audioManager.stopBluetoothSco(); 
audioManager.setBluetoothScoOn(false); 

所需的權限如下:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> 

很容易!

+0

優秀 - 這個答案爲我工作最好。我現在需要的只是一些檢測藍牙耳機的方法。 – ugoano 2014-02-01 21:06:25

+0

你可以用BroadcastReceiver來實現: public class BTReceiver extends BroadcastReceiver {int state = 0; (「Z」,「Received:Bluetooth」);以及其中, \t \t嘗試{ \t \t \t Bundle extras = intent.getExtras(); \t \t \t如果(臨時演員!= NULL){ //做一些事情 \t \t \t} \t \t}趕上(NullPointerException異常E){ \t \t \t Log.d( 「NPE」,「空指針異常「+ e.toString()); \t \t} \t} – 2014-07-16 12:56:20

+0

而且你需要在你的清單中添加此: <接收 機器人:名字= 「com.android.sam.receiver.BTReceiver」 機器人:啓用= 「真」 機器人:許可= 「android.permission.BLUETOOTH」> <意圖濾波器> <操作機器人:名稱= 「android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED」/> 2014-07-16 12:57:43

0

Hoan Nguyen做得很好!
測試他的代碼我注意到,在某些情況下,stopBluetoothSco()不會被調用。

我建議在CountDownTimer變化不大:

private CountDownTimer mCountDown11 = new CountDownTimer(10000, 1000) 
{ 
    @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
    @SuppressWarnings("synthetic-access") 
    @Override 
    public void onTick(long millisUntilFinished) 
    { 

     mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset); 

     Log.d(TAG, "onTick startVoiceRecognition"); //$NON-NLS-1$ 
    } 

    @SuppressWarnings("synthetic-access") 
    @Override 
    public void onFinish() 
    { 
     mIsCountDownOn = false; 

     /* START EDIT: Unregister broadcast receivers and stop Sco audio connection 
      and cancel count down if fails to connect. */ 

     stopBluetooth11(); 

     /* END EDIT */ 

     Log.d(TAG, "\nonFinish fail to connect to headset audio"); //$NON-NLS-1$ 
    } 
};