I am using AVPlayer to play music in my code. I know I can use MPVolumeView from MediaPlayer to route between speakers, but I am looking for something different(Because I am developing the application in Ionic and I am not able to find some plugin that can perform such thing, plugin which I use is cordova-plugin-media).
I have searched about how to create it and found some answers like I can switch using AVAudioSession.
I am not able to find some code related to it so if anyone can help it would be great.
Another thing is that if I change this forcefully how will it behave with Control Center.
You can still use MPVolumeView with IONIC as plugin, you just need to control UITouchUpInside through code.
Check this if helps.
- (void) currentOutputs:(CDVInvokedUrlCommand*)command {
if(!mpVolumeView){
mpVolumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];
mpVolumeView.showsVolumeSlider = FALSE;
[self.webView.superview addSubview:mpVolumeView];
[mpVolumeView setAlpha:0.01];
}
UIButton* btn = nil;
for (UIView *view in [mpVolumeView subviews]){
if ([view.class.description isEqualToString:#"MPButton"]){
btn = (UIButton*)view;
break;
}
}
if(btn){
[btn sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
Working plugin
https://github.com/jaymehtasa/cordova-plugin-audioroute
Have you tried this?
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionPortBluetoothA2DP)
} catch _ {
}
This maybe helpful.
Related
I'm using MobileVLCKit in form of MobileVLCKit-prod version 2.7.9 from CocoaPods.
I am initializing VLCMediaPlayer this way
VLCMediaPlyer *player;
....
player=[[VLCMediaPlayer alloc] init];
player.delegate=self;
VLCMedia * media;
media=[VLCMedia mediaWithURL:#"UrlOfRemoteAudiFile"]
I don't setup player.drawable because I only need audio and remote file doesn't contain video stream anyway.
Audio file plays correctly. Pause/resume works.
but I cannot change sound volume: player.audio.volume returns 0, attempts to assign player.audio.volume value in interval 0..200 are ignored with no change in volume.
I currently test on iOS9.
Only solution I found so far which works is changing system volume.
only way I find to do that (partially based on code from ttps://stackoverflow.com/questions/33168497/ios-9-how-to-change-volume-programmatically-without-showing-system-sound-bar-po ) is just change system volume.
code like this.
- (void) fakeSystemVolumeSetup:(float)newValue {
MPVolumeView* volumeView = [[MPVolumeView alloc] init];
// Get the Volume Slider
UISlider* volumeViewSlider = nil;
for (UIView *view in [volumeView subviews]){
if ([view.class.description isEqualToString:#"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)view;
break;
}
}
// Fake the volume setting
[volumeViewSlider setValue:newValue animated:YES];
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
}
It works and it turned out that having system indicators active is even better for this project.
I'm developing a radio streaming app with XCode 4.5 for iOS 6 and mainly using storyboards.
I successfully made it to be able to play in background. So wherever I go from my app, whether to other tabs or even after clicking the Home button on the simulator,it keeps playing.
I'm using Matt Gallagher's audio streamer, which I include in my app delegate .m file below
#pragma mark - audio streaming
- (void)playAudio:(indoRadio *)np withButton:(NSString *)currentButton
{
if ([currentButton isEqual:#"playbutton.png"])
{
[self.nowplayingVC.downloadSourceField resignFirstResponder];
[self createStreamer:np.URL];
[self setButtonImageNamed:#"loadingbutton.png"];
[audioStreamer start];
}
else
{
[audioStreamer stop];
}
}
- (void)createStreamer:(NSString *)url
{
if (audioStreamer)
{
return;
}
[self destroyStreamer];
NSString *escapedValue = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(nil,(CFStringRef)url,NULL,NULL,kCFStringEncodingUTF8);
NSURL *streamurl = [NSURL URLWithString:escapedValue];
audioStreamer = [[AudioStreamer alloc] initWithURL:streamurl];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playbackStateChanged:)
name:ASStatusChangedNotification
object:audioStreamer];
}
- (void)playbackStateChanged:(NSNotification *)aNotification
{
NSLog(#"playback state changed? %d",[audioStreamer isWaiting]);
if ([audioStreamer isWaiting])
{
[self setButtonImageNamed:#"loadingbutton.png"];
}
else if ([audioStreamer isPlaying])
{
[self setButtonImageNamed:#"stopbutton.png"];
}
else if ([audioStreamer isIdle])
{
[self destroyStreamer];
[self setButtonImageNamed:#"playbutton.png"];
}
}
- (void)destroyStreamer
{
if (audioStreamer)
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:ASStatusChangedNotification
object:audioStreamer];
[audioStreamer stop];
audioStreamer = nil;
}
}
- (void)setButtonImageNamed:(NSString *)imageName
{
if (!imageName)
{
imageName = #"playButton";
}
self.nowplayingVC.currentImageName = imageName;
UIImage *image = [UIImage imageNamed:imageName];
[self.nowplayingVC.playBtn.layer removeAllAnimations];
[self.nowplayingVC.playBtn setImage:image forState:0];
if ([imageName isEqual:#"loadingbutton.png"])
{
[self.nowplayingVC spinButton];
}
}
The problem I got is that when I click the play button, it starts the audio streamers but doesn't change into either loading button or stop button. This makes me unable to stop the audio since the button image is not changed. And since I put an NSLog inside the playbackStateChanged: method,I know that the playback state did change. It seems like the setButtonImagedNamed: method is not firing. Any thoughts?
Please have look of my answer:Disabled buttons not changing image in
For a button there is normal, selected, highlighted and disabled state.
So in your case you have to handle the normal and selected state.
In the xib, set image to a button for normal and selected state.
Now in the function of playAudio instead of checking the image name check the button state as below:
- (void)playAudio:(indoRadio *)np withButton:(NSString *)currentButton
{
if (playButton.selected)
{
//Stop the streaming
//set selection NO
[playButton setSelected:NO];
}
else
{
//Start the streaming
//set selection YES
[playButton setSelected:YES];
}
}
playButton is the IBOutlet of play button.
As you have set the images in xib, so the image automatically get changed as per the state of the image
In case you have added the playBtn programmatically, check if the button is declared as weak or its getting released somewhere. If it is weak, make it strong.
In case the button is in the nib file, then the problem is in the IBOutlet. Redo the connection properly.
It turned out that the delegate didn't know which nowplayingVC I was calling. #sarp-kaya's question about Calling a UIViewController method from app delegate has inspired me.
I actually have put this code in my view controller viewDidLoad:
myAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
but I forgot to add this line:
appDelegate.nowplayingVC = self;
So, all I need to do is adding that one line and it works now. okay, so silly of me for not noticing such a basic thing. But thanks for your helps :D
I used the following code to initial the text to speech synthesis using a button. But sometimes users may want to stop the voice in the middle of the speech. May i know is there any code i can do that.
Thanks
Here is my code
#interface RMDemoStepViewController ()
#end
#implementation RMDemoStepViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//Add Border to TextBox
//Instantiate the object that will allow us to use text to speech
self.speechSynthesizer = [[AVSpeechSynthesizer alloc] init];
[self.speechSynthesizer setDelegate:self];
}
- (IBAction)speakButtonWasPressed:(id)sender{
[self speakText:[self.textView text]];
}
- (void)speakText:(NSString *)toBeSpoken{
AVSpeechUtterance *utt = [AVSpeechUtterance speechUtteranceWithString:toBeSpoken];
utt.rate = [self.speedSlider value];
[self.speechSynthesizer speakUtterance:utt];
}
- (IBAction)speechSpeedShouldChange:(id)sender
{
UISlider *slider = (UISlider *)sender;
NSInteger val = lround(slider.value);
NSLog(#"%#",[NSString stringWithFormat:#"%ld",(long)val]);
}
#end
But sometimes users may want to stop the voice in the middle of the speech.
To stop speech, send the speech synthesizer a -stopSpeakingAtBoundary: message:
[self.speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
Use AVSpeechBoundaryWord instead of AVSpeechBoundaryImmediate if you want the speech to continue to the end of the current word rather than stopping instantly.
You can also pause speech instead of stopping it altogether.
This will completely stop the SpeechSynthesizer: -stopSpeakingAtBoundary and if you want more code after the SS, then put : at the end of that. So basically, -stopSpeakingAtBoundary: For the full code to fit in with yours, here: [self.speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
I added a button to my storyboard, and assigned a music to be played when the button is clicked. I used the event touch up inside
My question is, how can I make the button to toggle the music on and off when it is clicked.
Thanks
==================================================================================
For those of you who are interested in seeing the App, I made a repository on github. Here's the link https://github.com/edwinlimantara/IncrediboxV2. Please contribute, if you feel it is an interesting project.
I tried to make something similar to http://incredibox.com/v2/. Check it out! It is a very cool website.
If you are using AVAudioPlayer you can toggle the music player on button tap like:
if(audioPlayer.isPlaying){
[audioPlayer stop];
audioPlayer = nil;
}else{
// initialize audio player and play
}
You can do like below, say below method is called on button tap event then,
-(IBAction)pushClicked:(id)sender
{
UIButton *mButton = (UIButton*)sender;
if (mButton.selected==NO)
{
[mButton setSelected:YES];
//do your stuff here;
}
else if (mButton.selected==YES)
{
[mButton setSelected:NO];
// do your stuff here
}
}
Better you can use UISwitch rather than button to toggle.
If you want to use UIButton then you can use tags and and two different images.
if(soundButton.tag == 1)
{
if(audioPlayer.isPlaying){
[audioPlayer stop];
audioPlayer = nil;
soundButton.tag = 0;
// Change the button image to Off
}
else{
// initialize audio player and play
}
}
else
{
soundButton.tag = 1;
// Play the music & Change the button image to ON
}
I have created a webView:
videoView.delegate = self;
videoView.userInteractionEnabled = true;
[videoView loadRequest:[[NSURLRequest alloc]initWithURL:[[NSURL alloc] initWithString:#"website"]]];
I have html/javascript to handle the video's loading as well as the autoplay and next video. This all works, but my problem is that IOS autoloads the quicktime - like player, which is also a good thing, but I do not know how to control that, nor do I know how to get the video to play once that has happened. I would like the button that shows up in the player to autoplay. I would like that to happen anytime a new video is loaded.
JS code works like this. I take in a list and that is my playlist. I do not load a playlist from youTube I just make my own list and when end of video is called I load a new video by id. I also autoplay the video which is what gives me the button that IOS supplies anytime a video loads. Also, I am using an iframe to do all of this, with the youTube api's that is how I have control on the js side of things.
Question: Is there a way to control the play via code? If so how, also when the player is already loaded and I load another video how can I get that to autoplay as well?
I found the answer:
If you put webView.mediaPlaybackRequiresUserAction=FALSE; in the webViewDidFinishLoad then it will autoplay and still let you use the other buttons as well. This worked like a charm and suggest using it.
I found the answer: If you put
webView.mediaPlaybackRequiresUserAction=FALSE;
In the webViewDidFinishLoad: then it will autoplay and still let you use the other buttons as well. This worked like a charm and suggest using it.
To check if the playback is finished I used the following method:
First, set the delegate of your webview to self and implement this:
- (void)webViewDidFinishLoad:(UIWebView *)_webView {
UIButton *b = [self findButtonInView:_webView];
[b sendActionsForControlEvents:UIControlEventTouchUpInside]; //autoplay :)
[[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject] setTag:1234]; //tag it
}
then start a timer:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
and check:
BOOL playing;
- (void)onTimer:(NSTimer *)t {
id _topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
if ([_topView tag]==1234)
{
playing=YES;
}
else {
if (playing==YES) { //was playing, but now not anymore
//dismiss your view, or do other things.
[t invalidate];
playing=NO;
}
}
}