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.
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.
To reach to any solution for your problem, we must understand first what facility does car audio system provides with bluetooth.
Car audio system support A2DP profile along with HandsFree profile for attaining calls. Now, when bluetooth is selected as the source anything which is played by your app on A2DP profile will be played by audio system. However, once you've switched to other source like radio, even though your device is connected with A2DP profile with car audio system nothing will be played which you are facing now. However, few things that can be tried here, which interrupts the radio play as well are:
We know that when any call comes, we get alert with phone number even when we are listening to radio. This alert portion you can use for your solution. However, I dont know much if we can send phone ring alert from app. These alerts are at lower level just AT commands. Some search would be needed to check this.
In some car audio system, there is facility that when sms comes it alerts you. This alert part can also be explored.
I could see these two option which could help you. But this is not the only option I guess. Please try to find car audio systems bluetooth spec sheet. There you could know what other bluetooth alert features they provide.
I will update this answer I find any hint on my above suggestion.
Thanks
Related
This is an issue in MacBook Pro. I figured out the problem after few
hours of debugging
I am using the following code to create a media player and play an mp3 file. I am using the built-in emulator in Android Studio. Any suggestions for debugging?
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
MediaPlayer mediaPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayer = MediaPlayer.create(this,R.raw.music);
mediaPlayer.start();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ablejohnson.audiodemo.MainActivity">
</android.support.constraint.ConstraintLayout>
EDIT
For further debugging I added an onErrorListener for mediaPlayer
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
Log.e("error","what:"+what+",extra"+extra);
return false;
}
});
The following line is getting printed in logs.
D/Atlas: Validating map...
E/MediaPlayer: Should have subtitle controller already set
E/MediaPlayer: Error (1,-19)
E/error: what:1,extra-19
This is a specific issue in Emulator running on MacBook Pro. I tried to run the same app on actual devices and windows+ emulator both cases it was working fine.
The solution here is hacky but it worked for me
turn off Bluetooth and relaunch the emulated device
I quote the documentation, "A "raw" resource is a file that the system does not try to parse in any particular way. However, the content of this resource should not be raw audio. It should be a properly encoded and formatted media file in one of the supported formats."
Check if your music file is in a supported format.
Check out the doc for further details.
https://developer.android.com/guide/topics/media/mediaplayer.html
Support format:
https://developer.android.com/guide/topics/media/media-formats.html
I've been making a soundboard app of my infant son's sounds. The app simply opens to MainActivity class where it displays a scrollable list of buttons that, when pressed, will playback a pre-recorded MP3 of my son screaming something.
Once it's debugging or running on my Nexus 7 there is a Choreographer error and somewhere between 50 and 90 frames are skipped. The warning is that the 'application may be doing too much work on its main thread'. On my device three random buttons refuse to play sound until the app is closed and re-opened but then another three random buttons refuse to work. This problem didn't occur when my app only had eight buttons in a simple LinearLayout (without ScrollView).
I'm a beginner to both java and Android programming but, from what I guess, my laughably poor code is taking too much memory to properly function. My question is either, how would you code a scrollable list of 33 buttons that play their own sound, or could someone teach me how to better my code, please?
MainActivity.java (showing only the first three buttons/sounds for this question):
import android.media.MediaPlayer;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.view.View;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MediaPlayer ahh = MediaPlayer.create(this, R.raw.ahh);
final MediaPlayer dededeh = MediaPlayer.create(this, R.raw.dededeh);
final MediaPlayer neganegabunbunbug = MediaPlayer.create(this, R.raw.naganagbunbun);
Button bahh = (Button) this.findViewById(R.id.Ahhhbutton);
bahh.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ahh.start();
}
});
}
}
And the activity_main.xml (again with only the first three buttons for this question):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tab1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="#+id/Ahhhbutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:background="#layout/button_shape"
android:text="#string/button1a"
android:textColor="#d1d1d1"
android:textSize="20sp" />
<Button
android:id="#+id/dededehbutton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:background="#layout/button_shape"
android:text="#string/button1b"
android:textColor="#d1d1d1"
android:textSize="20sp" />
<Button
android:id="#+id/neganegabunbunbugbutton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:background="#layout/button_shape"
android:text="#string/button1c"
android:textColor="#d1d1d1"
android:textSize="20sp" />
Button bdededeh = (Button) this.findViewById(R.id.dededehbutton);
bdededeh.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dededeh.start();
}
});
Button bnaganagbunbun = (Button) this.findViewById(R.id.naganagabunbutton);
bnaganagbunbun.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
neganegabunbunbug.start();
}
});
</LinearLayout>
</ScrollView>
</LinearLayout>
It's not the layout. As your error said, you shouldn't do any long-term work on the Main-Thread.
The main-thread (or on Android the UI-Thread) handles interaction with the user. For the UI to not freeze and feel fast, you should execute long-term actions off the UI-Thread.
Also, the problem is not the actual playback, but you loading all media-files:
MediaPlayer.create(this, R.raw.ahh);
As the docs for the create()-method suggest:
[...] When done with the MediaPlayer, you should call release(), to
free the resources. If not released, too many MediaPlayer instances
will result in an exception.
For the "off the UI-Thread"-thing, you have three options:
Directly can create a Runnable-implementing class that plays your sound and submit it to a ScheduledThreadPoolExecuter (maximum control, more code).
Use an AsyncTask (Android exclusive) to play the song (fairly simple).
If you want the sound-playback to continue even when the app is not currently in the foreground, use a Service (most work)
So, what you should do is:
Store a List of your raw-file references (the R.raw.ahh) and don't load them directly.
When a song is selected for playback, call create() on that songs ID and start playback off the UI-Thread.
When done, call release() to release the resources.
I'am trying to develop app for tv streaming (HLS). Using code below I tested stream on 2.3.3, 3.0 and 4.0.1 version Android devices, but encountered several problems.
On Android 2.3.3 stream plays for >1 minute and then just stops. On Android 3.0 it plays well and on Android 4.0.3 it displays message 'This file cannot be played' (if I remember correctly).
So my question would be:
How can I play stream on ether of these devices, without having stream playing problems? Or where can I read more about solutions to these problems (tried to search but found nothing useful)?
Code in Main_Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VideoView player = (VideoView)findViewById(R.id.player);
String httpLiveUrl = "http://aj.lsops.net/live/aljazeer_en_high.sdp/playlist.m3u8";
//for Android 2.3.3 I used httplive:// prefix
player.setVideoURI(Uri.parse(httpLiveUrl));
player.setMediaController(new MediaController(this));
player.requestFocus();
player.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
Code in xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<VideoView
android:id="#+id/player"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Sorry if my english is poor.
Thank You.
This will not solve all the streaming issues. But one thing you should do is call player.start() when the MediaPlayer is ready. The selected answer to this SO post sets a listener on the MediaPlayer object so that it will run start() when onPrepared(MediaPlayer mp) is called.
Insert this Code to AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
I'm having trouble getting past the basics of having my app communicate with a server to store data.
I'm attempting to use Parse (https://parse.com/) as the backend of the Android app I'm working on. I got the basic "Quick Start" Parse app going fine, and was able to upload data from the app on my phone to my Parse account using the onCreate() method. Then I tried to create an app which would upload some data when a button is pressed. I can install and run the app, but when I press the button nothing seems to happen, and when I then check my Parse account no data has been uploaded. I included the Parse libs and added them to the build path.
Here is the app code-
package greg.mariani.saveLoad;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import com.parse.Parse;
import com.parse.ParseObject;
public class SaveLoad1Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
Parse.initialize(this, "private_app_token1", "private_app_token2");
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void saveUpdates(View view) {
ParseObject updates = new ParseObject("Updates");
updates.put("court", "Brentwood Rec");
updates.put("update", "Game On");
updates.saveInBackground();
}
}
Here is the layout 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="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/save"
android:onClick="saveUpdates"/>
</LinearLayout>
Can anyone see what I'm doing wrong?
have you added internet permission to your manifest file?
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
I am a PHP programmer who is having to do some work in the android development environment. I have 2 books on this and have tried 30 search engine topics and still have not found just a simple example of everything that you need to do to place a working hyperlink in a Java android application.
I just need a very simple but complete ingredient for doing so. I have the 2.2 android development environment with Eclipse and an emulator. I have tried the WebView control which just simply loads a web site into the window when I run the application. I need a basic hyperlink to a web site example.
I don't want anything else thrown in with it (just an application with a working hyperlink and nothing else), because I am trying to learn the different controls bit by bit along with the Java and XML code that controls them.
This is so different from PHP, ASP, etc. that it has me totally fishing for answers. Thanks;
Cullan
Android is a GUI, not a Web browser. Hence, "place a working hyperlink in a Java android application" is akin to "place a snowplow blade on a dishwasher" or "implement a Web app in COBOL". It is technically possible but probably is the incorrect solution to whatever problem it is that you really trying to solve.
So, as MatrixFrog indicates, one possibility is to use a TextView and some HTML:
TextView tv=(TextView)findViewById(R.id.whatever_you_called_it_in_your_layout);
tv.setText(Html.fromHtml("Who knows?"));
But, doing that would be unusual in a GUI environment. Most developers would use a button, or a menu choice, or something along those lines, to trigger viewing some URL.
CommonsWare, That is not what I call a detailed explanation or example of how to place a hyperlink inside an android application. It is just a small snippet of code with no further explanation. I found what works on my own and here is the Java code for it:
package com.practice.weblink;
import android.app.Activity;
import android.os.Bundle;
import android.text.util.Linkify;
import android.widget.TextView;
public class WebLink extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textview = (TextView) findViewById(R.id.hyperlink);
Linkify.addLinks(textview, Linkify.WEB_URLS);
}
}
The TextView has the following qualities in the main.xml file:
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="#string/hyperlink"
android:id="#+id/hyperlink"
android:autoLink="web"
>
</TextView>
The strings.xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WebLink</string>
<string name="hyperlink">http://google.com</string>
</resources>
That is how you give a working example of something. Next time don't assume that people can just piece together what you are mentioning in your answer.
How about using onClick in the XML layout file?
layout.xml
<TextView
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:clickable="true"
android:text="#string/market_url"
android:textColor="#00f"
android:onClick="openURL"
/>
MyActivity.java
public void openURL(View v) {
String url = ((TextView) v).getText().toString();
final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(url));
startActivity(intent);
}