Android Question [SOLVED] - Listening for when audio from a video or sound file is played from another app

rleiman

Well-Known Member
Licensed User
Greetings,

I'm currently using this coding to detect when the phone state changes when the phone app is on a phone call. Is there something like it to detect when audio from another app starts playing? I want to use the same type of coding to mute the exoPlayer volume as soon as another app wether it's a video or other audio starts playing.

Process_Globals:
Private PE As PhoneEvents
Private PhoneId As PhoneId

B4X:
Sub InitializeObjects
    PE.InitializeWithPhoneState("PE",PhoneId)
End Sub

B4X:
Sub PE_PhoneStateChanged (State As String, IncomingNumber As String, Intent As Intent)
    
    If kvs.Get("SoundIsOn") = True Then
        If State = "IDLE" Then
            exoPlayer.Volume = kvs.Get("MasterVolume")
        Else
            exoPlayer.Volume = 0
        End If
    End If
End Sub
 

JohnC

Expert
Licensed User
My first thought is that for a video or music file to play from another app, the user would usually switch away *from* your app to that other app to play the video/music.

For these cases, you should be able to simply pause exoPlayer when your app's activity is "paused" (the "Activity_Paused" event that automatically happens when focus is switched away from your app). And then simply resume exoPlayer when the user returns focus to your app (via your app's Activity_Resume event).

This "pause" method should also work when the user's phone rings without needing to monitor the phone's state because the OS will automatically switch away from your app and bring focus to the devices phone app.

But I don't know exactly what your app does, so this method might now be applicable.
 
Last edited:
Upvote 0

rleiman

Well-Known Member
Licensed User
My first thought is that for a video or music file to play from another app, the user would usually switch away *from* your app to that other app to play the video/music.

For these cases, you should be able to simply pause exoPlayer when your app's activity is "paused" (the "Activity_Paused" event that automatically happens when focus is switched away from your app). And then simply resume exoPlayer when the user returns focus to your app (via your app's Activity_Resume event).

This "pause" method should also work when the user's phone rings without needing to monitor the phone's state because the OS will automatically switch away from your app and bring focus to the devices phone app.

But I don't know exactly what your app does, so this method might now be applicable.
Hi John,

My app runs in the background and I'm currently checking video or other media sound with this coding:

B4X:
Sub IsMediaPlaying As Boolean

    Dim JO As JavaObject
    JO.InitializeContext

    If JO.RunMethodJO("getSystemService",Array("audio")).RunMethod("isMusicActive",Null) = True Then
        Return True
    Else
        Return False
    End If       
End Sub

Since the app is running in the background I'm hoping to find something can listen for when another app starts to make sound. That would give my app the heads up to mute my app's volume.
 
Upvote 0

JohnC

Expert
Licensed User
Oh, so you have code to detect if audio is playing from another app, but you are looking for an event to do this check so you wont have to keep calling this routine in a loop, right?
 
Last edited:
Upvote 0

rleiman

Well-Known Member
Licensed User
Oh, so you have code to detect if audio is playing from another app, but you are looking for an event to do this check so you wont have to keep calling this routine in a loop?
Kind of. I call it before playing sound from my app. I actually use 2 exoPlayers to play sounds. I could use one player but I use 2 of them because I want both to play at the same time. The problem is when one player is playing, that coding returns true wether something is playing in another app or from within my own app. That makes it difficult to mute my app because I only want to do it if the sound that's playing is from another app and not mine.
 
Upvote 0

JohnC

Expert
Licensed User
Without knowing what your app actually does and why it does it, it is difficult to come up with more ideas because I don't fully understand the boundaries of the use-case.
 
Upvote 0

rleiman

Well-Known Member
Licensed User
Without knowing what your app actually does and why it does it, it is difficult to come up with more ideas because I don't fully understand the boundaries of the use-case.
It's basically a clock app that ticks and plays Westminster chimes on the quarters. Everything works on the app without any issues. It uses 2 players. One is for a constant ticking sound and the other player is for the chimes. All of the sounds come from sound files. When the app is ready to chime it checks if media is currently playing. If it is, the app remains silent otherwise it will chime.

What I would like to do is have the ticking constantly run then introduce the chiming as needed. Currently the only way to get both the ticking and the chimes to play at the same time is not check for media playing. The coding that checks for media playing does not differentiate between sounds from my app and sounds from another app. By having the ticking going constantly, the media playing sub routine will always return "True" because of the ticking being played. I would like to be able to know using some kind of listening that detects sounds playing outside of my app right when they start to play so I can first mute the ticking and then the chiming as needed just like I do when the phone state changes.

I hope this kind of makes it easier to understand what I'm trying to do. It's a tricky one. ;)
 
Last edited:
Upvote 0

JohnC

Expert
Licensed User
That info is helpful.

How often does each "tick" sound? My thought is to play the tick sound via a timer and do the sound check in between the ticks:

For example, lets say the ticks happen every 1 second (1000 milliseconds) and to play a single tick sound itself takes 250 milliseconds. So you want to make sure that when you check for external audio, it is well past the time it took to play the single tick sound. That is why in this example I set the second timer to 500ms, so you wont falsely detect the tick sound as an external audio.

Steps:
1) @ the 0ms mark - play tick sound then start a 1000ms timer
2) immediately start a 500ms timer (this should trigger well after the time it took to play the above tick sound)
3) @ the 500ms timer trigger mark, do an audio check - the result should be false if no other app is playing audio - save this result in a global variable for use by the next step.
4) @ 1000ms "tick" timer trigger mark, if the audio check was false at step 3 above, then loop back to step 1 above and play the tick sound again. If step 3 was true (there was external audio playing), then loop back to step 2 above (and don't play the tick).

Note: I have not used the exoPlayer yet, but if it has a "Done_Playing" event, then you could eliminate the 500ms timer and simply do the external audio check when this "done" event happens.
 
Last edited:
Upvote 0

rleiman

Well-Known Member
Licensed User
That info is helpful.

How often does each "tick" sound? My thought it to play the tick sound via a timer and do the sound check in between the ticks:

For example, lets say the ticks happen every 1 second (1000 milliseconds) and the tick sound itself takes 250 milliseconds to play

Steps:
1) @ the 0ms mark - do tick sound then start a 1000ms timer
2) immediately start a 500ms time
3) @ the 500ms timer trigger mark, do an audio check - the result should be false if no other app is playing audio, and if false, then it is OK to play the next tick sound in 500ms.
4) @ 1000ms timer trigger mark, if the audio was false at the 500ms mark, then loop back to step one above. If there was audio playing, then loop back to step 2 above.
The app is using a 1 second timer and inside the tick sub routine is where I do the audio check ticks and chimes as needed.

Later I will try your logic.

Thanks for the suggestion.
 
Upvote 0

JohnC

Expert
Licensed User
Alternatively, you could do the audio check right before you play the tick sound - that should prevent you from falsely detecting the tick as external audio because when you do the check, your app has not yet played the tick sound.
 
Upvote 0

rleiman

Well-Known Member
Licensed User
Alternatively, you could do the audio check right before you play the tick sound - that should prevent you from falsely detecting the tick as external audio because when you do the check, your app has not yet played the tick sound.
Thanks. Very helpful. ;)
 
Upvote 0

JohnC

Expert
Licensed User
Thanks. Very helpful. ;)
This way you don't need a "Done_Playing" event or the 500ms timer.

*** And you wont have to change the volume at all.

So basically, you would have the 1000ms timer routine like this:
B4X:
Sub tmr1000ms_Tick    'this happens every 1 second
    'we do the audio check BEFORE playing anything so there is minimal chance of the check falsely detecting our app's audio
    If IsMediaPlaying = False then  'if no external audio playing, then its ok to play tick/chime below

          If TimeToPlayQuarterlyChime then   'if its on the 15 min/quarterly of hour, then
              PlayChimeSound  'play quarterly chime sound instead of tick sound
          else
              PlayTickSound    'play the one second tick sound
          end if
 
    end if

End Sub
 
Last edited:
Upvote 0

Peter Simpson

Expert
Licensed User
Right @rleiman,
I have finally read your posts correctly, I think, @JohnC please let me know if I have got this incorrect.

@rleiman has 2 apps running, one plays constant ticks, and the other plays a chime every 15 minutes. What he wants is that when the 15 minute app is ready to play a chime but he also wantsexoplayer to pause first so that he can hear that chime?

Is this what @rleiman is after??

If so then one solution is to get the 15 minute app to send an intent that tells his exoplayer to pause thus the 15 minute app can then play its chimeand be heard. The exoplayer is specifically listening for the 15 minute app broadcast of its intent, when the exoplayer broadcastreceiver receives the intent, exoplayer will pause, thus allowing the 15 minute app to chime so it can be heard.
 
Upvote 0

JohnC

Expert
Licensed User
What I understand the situation to be is that he has one app, but is using two exoplayers to play sounds - one to play ticks and the other chimes.

But he doesn't want his app to make any sound if there is *another* app on the device playing audio.

Apparently the "IsMediaPlaying" function in post #3 can detect if audio is playing on the device for *ANY* app so he needs a way to make sure it only checks for external audio, which my example will hopefully do.
 
Last edited:
Upvote 0

rleiman

Well-Known Member
Licensed User
Right @rleiman,
I have finally read your posts correctly, I think, @JohnC please let me know if I have got this incorrect.

@rleiman has 2 apps running, one plays constant ticks, and the other plays a chime every 15 minutes. What he wants is that when the 15 minute app is ready to play a chime but he also wantsexoplayer to pause first so that he can hear that chime?

Is this what @rleiman is after??

If so then one solution is to get the 15 minute app to send an intent that tells his exoplayer to pause thus the 15 minute app can then play its chimeand be heard. The exoplayer is specifically listening for the 15 minute app broadcast of its intent, when the exoplayer broadcastreceiver receives the intent, exoplayer will pause, thus allowing the 15 minute app to chime so it can be heard.
Hi Peter,

John has it correct. It's one app that uses 2 exoPlayers but I want both playing together only if no external app's sound is playing. For example, if the user is looking at a video on the YouTube app I don't want the chiming app to play the chimes or the ticks until the user is finished with at the the YouTube video. I'll make a small app tomorrow to try out his logic.
 
Upvote 0

Peter Simpson

Expert
Licensed User
What I understand the situation to be is that he has one app, but is using two exoplayers to play sounds - one to play ticks and the other chimes.

But he doesn't want his app to make any sound if there is *another* app on the device playing audio.

Apparently the "IsMediaPlaying" function in post #3 can detect if audio is playing on the device for *ANY* app so he needs a way to make sure it only checks for external audio, which my example will hopefully do.

Thank you for that @JohnC 👍
 
Upvote 0

Peter Simpson

Expert
Licensed User
Hi Peter,

John has it correct. It's one app that uses 2 exoPlayers but I want both playing together only if no external app's sound is playing. For example, if the user is looking at a video on the YouTube app I don't want the chiming app to play the chimes or the ticks until the user is finished with at the the YouTube video. I'll make a small app tomorrow to try out his logic.

Man, that's confusing o_O
 
Upvote 0

rleiman

Well-Known Member
Licensed User
This way you don't need a "Done_Playing" event or the 500ms timer.

*** And you wont have to change the volume at all.

So basically, you would have the 1000ms timer routine like this:
B4X:
Sub tmr1000ms_Tick    'this happens every 1 second
    'we do the audio check BEFORE playing anything so there is minimal chance of the check falsely detecting our app's audio
    If IsMediaPlaying = False then  'if no external audio playing, then its ok to play tick/chime below

          If TimeToPlayQuarterlyChime then   'if its on the 15 min/quarterly of hour, then
              PlayChimeSound  'play quarterly chime sound instead of tick sound
          else
              PlayTickSound    'play the one second tick sound
          end if

    end if

End Sub
Hi John,

I just looked at your code. My app is already set up with similar logic. I doesn't work for me because
Man, that's confusing o_O
:eek:
 
Upvote 0

JohnC

Expert
Licensed User
I just looked at your code. My app is already set up with similar logic. I doesn't work for me because

"Because..." (I think your response got cut-off)

Because of why?
 
Upvote 0

rleiman

Well-Known Member
Licensed User
Man, that's confusing o_O
What I understand the situation to be is that he has one app, but is using two exoplayers to play sounds - one to play ticks and the other chimes.

But he doesn't want his app to make any sound if there is *another* app on the device playing audio.

Apparently the "IsMediaPlaying" function in post #3 can detect if audio is playing on the device for *ANY* app so he needs a way to make sure it only checks for external audio, which my example will hopefully do.

Hi John,

I just looked at your code. My app is already set up with similar logic. I doesn't work for me because the coding in post #3 detects both internal and external media playing. Also the current coding will not play both the ticking and the chiming together. I need a way to test only for when the external media is playing. Sorry for the confusion.
 
Upvote 0
Top