I am using Android TTS to speak a text. The speaking is done on a service. I am using TTS..speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null); my speak() function is called several times, during intervals. Because it is a service, its possible that other sounds are playing while speak() is called.
I want to know how to 'silence' those other sounds WHILE my text is being spoken.
The term you need to search for is 'audio ducking'. It's not an obvious one, so you can be forgiven for not finding any solutions with other search terms!
Check out the suggested way to handle this in the tutorial here.
I assume you will want to just lower any other media volume so the speech can be heard = ducking.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
Alternatively, you can request that other apps silence any media, until your onUtteranceCompleted is called and you release the audio focus. Beware though, if the other apps aren't handling the loss and gain of focus correctly, their media will not restart and your user will probably be annoyed...
Related
I am trying to write an app that detects whenever any app on the device starts or stops playing music. My app is not a media player, it's more of a dashboard functionality, so I have no need of requesting audio focus, but I want to know when other apps do so I can update my status text accordingly.
Essentially, I believe that the function AudioManager.isMusicActive() will provide essentially exactly what I want to know, however since I am writing a service that will be always on I would like to avoid needing to poll that on a constant basis. I need the information in near real time, so it would essentially be a 1 second poll in perpetuity.
I'm looking for a way to detect when STREAM_MUSIC is being used by another app.
Some ways I have thought about doing it:
(1) Again, a perpetual poll using either Timer or Handler to constantly poll the isMusicActive() function. Not ideal from a battery or processor management perspective. I could use a flag variable in the UI Activity to control when the poll runs (it isn't really necessary when the UI isn't in the foreground, anyways), but I still think I'm using more processor/battery time than I'd need to.
(2) Listen for a broadcast of some kind, but none of the Android audio broadcasts seem to really fit the bill. (that I could find)
(3) I could, I suppose, request audio focus and just never play any audio and never give it up. Theoretically, since I am starting this in an always on service I believe that should allow my app to sit at the bottom of the LIFO audio focus stack and I would be notified via the AudioManager.OnAudioFocusChangeListener mechanism in basically the opposite way of its intended purpose (i.e. turn on my app when I lose audio focus and turn it off when I gain audio focus back). However, I'm not entirely sure how doing something like this would function in real-life usage. I feel like abusing the audio focus methodology for something like this could very easily result in negative user experiences in situations I haven't even thought of.
(4) Is there a way to use the AudioManager.OnAudioFocusChangeListener (or similar) without needing to request audio focus at all?
Are there any other ways I could go about doing this? Just a pointer in the right direction would be incredibly helpful!
I needed similar thing, so did a bit of research.
Unfortunately, there seems to be no other way to accomplish this except of requesting audio focus in your app.
Material for study:
Check Android source code in frameworks\base\media\java\android\media\ where you can find actual code for requestAudioFocus in MediaFocusControl class.
Other classes in this folder show how they send broadcast events for volume change, bluetooth on/off, etc, but no broadcast event at all related to audio enabled/disabled.
Another information on topic:
http://developer.android.com/training/managing-audio/audio-focus.html
http://developer.android.com/training/managing-audio/audio-output.html
Other than that, there doesn't seem to be any documented way to know when audio hardware starts/stops to play.
I trust that requesting audio focus without actually playing audio should not consume any battery. Only one ugly side effect is that this stops currently played audio.
I am unable to clear myself that why do we need to use prepare() method in Mediaplayer. Why start() independently doesn't work in music players...
The prepare method collects metadata about the file or stream to be played, which may be necessary for proper function of the player itself and related components (like UI). The fact that you can call prepare and prepareAsync separately from calling setDataSource or start is simply a means of allowing the developer control over when and how things happen to suit his/her particular circumstance. Particularly for streaming media, preparation may take a significant amount of time, and so doing things the same way all the time will not be ideal in every situation.
suppose if you want doing some work that can be possible when media player is collecting infoemation then what you do. if start() work for both what happened if media player is collecting information about media. this will be treated as playing and it crashes completely. these are the states and has there works.
I am currently working on an audio player that is supposed to pause/stop when losing audio focus, for example when a call comes in.
While I got this working fine by using an OnAudioFocusChangeListener I want to enhance this function to behave differently under different circumstances.
As the application implements a timeout function in case the user has fallen asleep while listening I only want to resume playback when I can be positive that the user is still awake.
I figured I could pretty much ignore notification sounds like those of an incoming email, as these usually are only short clips and my audio continuing to play will not be a nuisance to the user, as it would be during a phone call.
Thus I want to limit pausing/stopping to situation where either a phone call comes in or the user makes a call.
I have seen that AudioManager has some convenient states to signal this, but upon calling AudioManager.getMode() in my OnAudioFocusChangeListener I do not get consistent output.
Sometimes an incoming call does generate MODE_RINGTONE, but often enough to render the function unreliable I get MODE_NORMAL.
I could actually live with not knowing the mode when losing focus as long as I get the correct mode when re-gaining focus, but also this doesn't seem to work reliably.
The only actual device I could test this behavior on is the Galaxy S2, running Android 2.3.6 (the application is API level 10 due to me using MediaMetadataRetriever, thus requires at least 2.3.3).
I have tested the loss and re-gaining of audio focus in various emulated systems, and overall it seems to be working better there, but I also don't really get the same results each time.
Maybe the problem is that I misunderstand what AudioManager.getMode() should return, maybe somebody could clarify this for me:
phone rings -> AudioManager.getMode() should return MODE_RINGTONE on focus loss
user makes or picks up a call -> AudioManager.getMode() should return MODE_IN_CALL on focus loss
doesn't pick up the call -> AudioManager.getMode() should return MODE_RINGTONE on focus gain
user hangs up -> AudioManager.getMode() should return MODE_IN_CALL on focus gain
Is that the way it is supposed to work? At least my tests suggest that this is the way it is supposed to be, but for some reason isn't all the time.
Another way I am trying to solve this problem is by using a PhoneStateListener, but the problem I have with this is that this requires my application to request the permission to read the phone state. As I am sharing my application, currently through SourceForge, later possibly through the Android Market, I would like to avoid using this kind of permissions.
So, coming to an end I would like to ask if the way I understand AudioManager.getMode() is correct and if there is any information on its reliability, as for me the results I get from it are kinda useless.
I have a simple app, which plays a short sound repeatedly, by invoking the play() method on the audio element in JavaScript. It works well on desktop browsers, ipads, iphones, etc. On a mobile device running Android 2.3.3, the first time I play the sound, I hear it immediately after invoking the play() method, but on subsequent invocations, there is a noticeable and variable delay.
I have done some sleuthing and found that the device is fetching the audio file from the server each time the play() method is invoked. I can invoke the load() method on the audio element to re-load it after each play, thus queueing it up for the next play, but there are a number of problems with that band-aid. I'd really like to make the browser just keep the audio element loaded permanently, instead of unloading it as soon as it finishes playing. Does anyone know if that's possible?
EDIT: I've done a little more investigating, and I've found that after playing the sound, the audio element's readystate remains at HAVE_ENOUGH_DATA, even though the browser won't play that sound again without re-fetching it from the server. I believe this is a bug. I'd hoped to use the readystate to detect browsers that unload after playing, and only explicitly load if necessary, but that's not going to work.
The more experiments I do, the more rough edges I find in Android 2.3.3's implementation of the HTML5 audio tag. There's a lot broken there, at least on the Droid X phone I'm using for testing.
The best I have come up with so far is the band-aid alluded to in my original question: as soon as an invocation of play() completes, invoke the load() method, to prepare for the next play():
if (navigator.userAgent.toLowerCase().indexOf("android") > -1)
audElt.addEventListener('ended', function () {
var t = setTimeout(function () { audElt.load(); }, 1000);
}, false);
I had to restrict the work-around to Android user agents, because simply invoking the load() method creates problems on Chrome and generates unnecessary trips to the server on non-Android systems.
I had to add a 1-sec delay, because if I simply invoked load() from the "ended" handler, it interrupted the playback, which, apparently, hadn't really "ended" yet....
Of course, it's still fetching the sound from the server repeatedly, so if you try to play the sound multiple times in rapid succession, things go south quickly.
best solution i've found. Another options is to just use the video tag but there are some problems with that as well. Nothing seems to work good enough to implement.
luckily im using phone gap so I'll give their audio methods a shot.
You can bind on updatetime to pause() the playback a second before reaching the end of the audio and rewind before playing it again. Android will not flush the audio then.
The Google Voice Search comes with a significant delay from the moment you call it via startActivityForResult() until its dialog box is displayed, ready to take your speech.
This requires the user to always look at the screen, waiting for the dialog box to be displayed, before speaking.
It would be nice to add a 'ding' sound or some other non-visual cue to when Voice Search is ready to accept speech input.
Is this possible at all?
If so, how do go about doing that?
Ok this will complicate your program, however, if you really want that signal consider implementing the speech recognition by an object instead of calling the intent or making your own activity.
(warning: much of this is speculation including the order of calls)
Perhaps the delay is in instantiating resources before actually listening. If my theory is correct than you could setRecognitionListener(RecognitionListener listener) (the latency passes), create a recognizerIntent object (maybe some more latency passes), finally in (an overridden) startListening(Intent recognizerIntent), call a "PING!" before calling the super method.
It is up to you whether you would like to wrap all this functionality in a new activity, which is probably recommended, or to tack on the latency to the UI.