Search code examples
androidbluetoothtext-to-speechvoipandroid-audiomanager

Interrupt car radio android bluetooth


We're trying to play audio alerts from our android app (traffic information) over bluetooth connected car stereos. If we switch the car stereo audio input to bluetooth, the app audio plays. If it is on any other source, the app audio does not play, either from the stereo or from the device.

What we want to do, is to allow users to keep the stereo audio input on DAB/FM radio or other source, but have our app audio interrupt at certain times and play these traffic information alerts, like how VOIP apps manage to do (such as Facebook messenger), and the built-in telephony phone call app manages to do.

Here is the code we are using at the moment :

MainActivity.java

package com.robbresearch.ttsandroidtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.content.Context;
import android.media.AudioManager;

public class MainActivity extends AppCompatActivity {

    private Button speakNowButton;
    private TextView textView;
    TTSManager ttsManager = null;
    AudioManager am;

    AudioManager.OnAudioFocusChangeListener afChangeListener =
        new AudioManager.OnAudioFocusChangeListener() {
            public void onAudioFocusChange(int focusChange) {
                if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                    // Pause playback
                } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                    // Resume playback
                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                    //am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
                    am.abandonAudioFocus(afChangeListener);
                    // Stop playback
                }
            }
        };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Context mContext = getApplicationContext();

        ttsManager = new TTSManager();
        ttsManager.init(this);

        am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);

        // Request audio focus for playback
        int result = am.requestAudioFocus(afChangeListener,
                // Use the music stream.
                AudioManager.STREAM_VOICE_CALL,
                // Request permanent focus.
                AudioManager.AUDIOFOCUS_GAIN);

        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            //am.registerMediaButtonEventReceiver(RemoteControlReceiver);
            // Start playback.
        }

        am.setMode(AudioManager.MODE_IN_CALL);
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

        textView = (TextView) findViewById(R.id.input_text);
        speakNowButton = (Button) findViewById(R.id.speak_now);
        speakNowButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                String text = textView.getText().toString();
                ttsManager.initQueue(text);
            }
        });
    }

    /**
     * Releases the resources used by the TextToSpeech engine.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        ttsManager.shutDown();
    }
}

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_marginBottom="10dp"
    android:orientation="vertical"
    android:padding="20dp" >

    <TextView
        android:id="@+id/input_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:ems="10"
        android:padding="10dp"
        android:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." />

    <Button
        android:id="@+id/speak_now"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Speak Now" />

</LinearLayout>

We have these additional permissions in android manifest :

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

We would greatly appreciate any advice on how to achieve this, thanks :)

We only need to support newer versions of android if necessary.


Solution

  • I was able to get it working with the following code :

    audioM.setMode(audioM.MODE_IN_COMMUNICATION);
    audioM.setBluetoothScoOn(true);
    audioM.startBluetoothSco();
    audioM.setSpeakerphoneOn(false);
    

    And the following permissions :

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

    There was no need to set thread priority or request audio focus.

    Note that I'm currently getting a 15 second delay between calling TextToSpeech.speak() and hearing the audio over the car radio. When I've solved that I'll update this answer.