How to disable seeking on iOS AVPlayerViewController? - ios

On tvOS if I want to allow play / pause but disable seeking, I can set avPlayerViewController.requiresLinearPlayback = YES. However this property doesn't exist in iOS. How would I accomplish the same on iOS? I don't want to use avPlayerViewController.showsPlaybackControls = NO because this would prevent play / pause. I only want to disable seeking. Furthermore, I'm not entirely sure that avPlayerViewController.showsPlaybackControls = NO would even fully prevent seeking, as someone could plug in a headset with control buttons on it and press the physical "skip forward" button

I solved this problem by extending AVPlayer. Despite the Apple documentation saying that you should not extend AVPlayer and doing so has undefined behavior, in test everything worked fine on iOS 9 through 13
#interface CustomAVPlayer : AVPlayer
#property BOOL seekingEnabled;
#end
#implementation CustomAVPlayer
- (instancetype)initWithPlayerItem:(AVPlayerItem *)item
{
self = [super initWithPlayerItem:item];
if (self) {
_seekingEnabled = YES;
}
return self;
}
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter completionHandler:(void (^)(BOOL))completionHandler
{
// This prevents seeking at the lowest level, regardless of whatever shenanigans the view may be doing
if (_seekingEnabled)
[super seekToTime:time toleranceBefore:toleranceBefore toleranceAfter:toleranceAfter completionHandler:completionHandler];
else
[super seekToTime:self.currentTime toleranceBefore:toleranceBefore toleranceAfter:toleranceAfter completionHandler:completionHandler];
}
#end
Now I can enable/disable seeking with just: player.seekingEnabled = (YES/NO);

Related

Overlaying background sound

we are having problem with our background sound. If the sound is on when we change view and then go back to the menu it adds another loop of sound. If the sound is muted when we go back it starts again. Please help. This is my code.
// Meny.m
#import "Meny.h"
#import <AVFoundation/AVFoundation.h>
#interface Meny () {
AVAudioPlayer *audioPlayerBG;
}
#end
#implementation Meny
- (void)viewDidLoad {
[super viewDidLoad];
NSString *music = [[NSBundle mainBundle]pathForResource:#"TestSwoong" ofType:#"wav"];
audioPlayerBG = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
audioPlayerBG.numberOfLoops = -1;
audioPlayerBG.volume = 0.5;
[audioPlayerBG play];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
// LjudKnapp stop
- (IBAction)stopBG:(id)sender {
[playBG setHidden:NO];
[pauseBG setHidden:YES];
[audioPlayerBG stop];
}
// LjudKnapp play
- (IBAction)playBG:(id)sender {
[pauseBG setHidden:NO];
[playBG setHidden:YES];
[audioPlayerBG play];
}
It appears that you need to brush up on what classes and instances are. Understanding classes and instances is fundamental if you're going to do object-oriented programming, which is what you do when you use Objective-C.
we change view and then go back to the menu it adds another loop of sound
That phrase suggests that when you "go back", you are not actually going back to the already existing Meny instance - instead, you are creating another Meny instance. So now, you see, you have two of them! Well, each Meny instance has its own AVAudioPlayer, which starts playing when the Meny instance is created — so now you have two audio players, and that's why you hear two loops playing simultaneously.

Forcing app to use Apple Keyboard in iOS 8

How can I get my app's UITextfields to only use the Apple keyboard in iOS 8? I do not want to allow third party keyboards, period. I understand it may be bad user experience so please don't discuss that point with me :)
I know I can set the securedEntry property to true to force the Apple keyboard (http://www.imore.com/custom-keyboards-ios-8-explained). Maybe iOS 8 will let me set this property and NOT mask the text?
Apple provides an API for exactly that. Put this in your AppDelegate
- (BOOL)application:(UIApplication *)application
shouldAllowExtensionPointIdentifier:(NSString *)extensionPointIdentifier
{
if ([extensionPointIdentifier isEqualToString:#"com.apple.keyboard-service"]) {
return NO;
}
return YES;
}
This is the cleanest and documented way to do it :)
By setting a UITextView or UITextField's property of Secure Text Entry to YES, custom keyboards will not be shown by default and can also not be toggled to.
This will also, unfortunately, hide key press information as well as over-ride and disable auto caps and auto correct and spelling suggestions. So you have to toggle is back off to NO after you're done forcibly making the user use Apple keyboard.
Toggling this property on and then off can force the Apple Keyboard to be the first key that displays by default.
NOW, the user will still be able to press the global key so you have two options:
•One, you can just let them and detect if they do using [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(inputModeDidChange:) name:#"UITextInputCurrentInputModeDidChangeNotification"
object:nil]; and just reloop the secureTextEntry code above and force switch back to Apple default keyboard (unprofessional method, but very easy to program). (*Note! This will also prevent users from being able to use the dictation keyboard (clicking the microphone icon button next to the space bar), unless you use undocumented code to detect if it's dictation or not (which does exist and has supposedly passed Apple validation on a few accounts. Info on this can be found here)
Or
•Two: to use UIWindows to get ONTOP of the default keyboard and add a UIWindow with userInteractionEnabled set to YES covering where that key is location (this will take a few conditional statements to make sure you're covering the right "change keyboard key" for every possibility. (i.e. landscape keyboard iPhone4, portrait keyboard iPhone5, etc).
Here is some demo code though of it working for portrait keyboards (iphone5 and iphone4)
viewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate> {
UITextField *theTextField;
UIWindow *statusWindow;
}
#end
viewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
theTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 50, 50, 250)];
[theTextField becomeFirstResponder];
theTextField.secureTextEntry = YES;//turn back OFF later (like in `viewDidAppear`) and reset textField properties to YES (like auto correct, auto caps, etc).
theTextField.delegate = self;
[self.view addSubview:theTextField];
//UIWindow *statusWindow; MUST be defined in .h file!
statusWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
statusWindow.frame = CGRectMake(37, self.view.frame.size.height-47, 45, 45);
statusWindow.windowLevel = UIWindowLevelStatusBar;
statusWindow.hidden = NO;
statusWindow.backgroundColor = [UIColor clearColor];
UIButton *keyboardCover = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
keyboardCover.backgroundColor = [UIColor redColor];
[statusWindow addSubview:keyboardCover];
//statusWindow.alpha = 1.00;
statusWindow.userInteractionEnabled = YES;
[statusWindow makeKeyAndVisible];
}
-(void)viewDidAppear:(BOOL)animated {
[theTextField resignFirstResponder];
theTextField.secureTextEntry = NO;
theTextField.autocorrectionType = 2;//ON
theTextField.autocapitalizationType = 2;//ON
theTextField.spellCheckingType = 2;//ON
[theTextField becomeFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here is an example of what that code will look like... I was using a custom keyboard, when I launched the app it forced me over to the Apple keyboard, then put a red square over the "change keyboard" button, which made it impossible for me to click the button to change the keyboard. (the red square can be changed to be anything of course like a blank key or the globe icon in a faded (disabled) state.)
To the best of my knowledge, there is no way to do this. However, if you're willing to put in the effort, you could create your own custom input view that mimics the standard Apple keyboard, and use that instead. For more on input views, refer to the documentation.

CvPhotoCamera and memory warning

I have a question about CvPhotoCamera (OpenCV) in the iOS App.
I have a myViewController1: in this viewController I push a mySecondView controller.
In this second View Controller I use CvPhotoCamera:
I have a UIImageViewController.
In viewDidLoad I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_photoCamera = [[CvPhotoCamera alloc] initWithParentView:imageView];
_photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetPhoto;
_photoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
[_photoCamera setDefaultAVCaptureDevicePosition:AVCaptureDevicePositionBack];
_photoCamera.delegate = self;
[_photoCamera start];
}
in viewDidDisappear I have this code:
- (void) viewDidDisappear:(BOOL)animated
{
[_photoCamera stop];
}
I use CvPhotoCamera to take a photo from camera using the method:
- (IBAction)actionStart:(id)sender;
{
[_photoCamera takePicture];
}
The my problem is this:
When I push this second ViewController and I tap on back button on Nav bar I have some memoryWarning and the app crashes ..always!!!
I used also the profile Xcode tool to manage memory allocation or memory leak but I do not see anything strange.
Is correct this use of CvPhotoCamera obj?

How to stop the voice during text-to-speech synthesis?

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];

iOS 7 and the MPMediaPicker, why plus?

I've got two strange diverging behaviours between iOS 6 and 7.
I want to present the MPMediaPicker to the end user, allow them to select 1 song, and start playing that back to them.
So, I show them the MPMediaPicker (/not/ multi, and /not/ cloud, if supported).
Two problems:
In iOS6, the first screen in MPMediaPicker shows the songs. In iOS7,
it's the (empty) playlists. How can I force the MPMediaPicker to
show songs as the default first screen? Is this just another example of Apple "knowing best"?
In iOS7 I get a red (+) symbol next to the media items in the list. What
causes that? I haven't been able to turn up any references for that
in google. What is the (+) symbol? It doesn't seem to highlight separately from the line in the table. The native media picker doesn't display this.
Thanks!
-Ken
Our MPMediaPicker code:
- (void)showSongPicker {
// TODO check if iOS 6
MPMediaPickerController* songPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
songPicker.delegate = self;
songPicker.allowsPickingMultipleItems = NO;
songPicker.showsCloudItems = NO;
[self presentViewController:songPicker animated:YES completion:nil];
[self presentModalViewController:songPicker animated:YES];
}
#pragma mark MPMediaPickerControllerDelegate
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
MPMediaItem* item = [mediaItemCollection.items objectAtIndex:0];
[self playMediaItem:item];
[self mediaPickerDidCancel:mediaPicker];
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
[self dismissViewControllerAnimated:YES completion:nil];
}
Oh! I do apologise. I'd forgotten to answer this.
Since I didn't get an answer from anyone else (until just now, thanks, lap.felix), I filed it as a technical question with Apple.
Their answer?
There's no programmatic way to affect the behaviour of the picker. If you need to change the behaviour this "drastically", you have to roll your own media picker.
So...yeah...thanks, Apple.
-Ken
The + doesn't mean anything other than "Add this item to the picker selection"

Resources