Bonjour NSNetServiceBrowser in iOS6 Not working - iphone

I'm working on advertising a desktop client to phones on the local network. My phone is at 6.0.2 with the Xcode 4.5.2.
I know the desktop app is registering successfully because the Discovery app (by Tildesoft) on my phone shows my service on the network (which also rules out wifi problems).
I've downloaded the Apple app example, Bonjour Web. The delegate for finding "_myservice._tcp" didn't ever fire, but the start browsing method does fire.
I tried using HHServices (which wraps DNSService), and while the start browsing method fired, the service found method doesn't fire.
In my own app, I tried using NSNetServiceBrowser. I set the delegate, and my "netServiceBrowserWillSearch" delegate method gets fired, but nothing else happens.
Code is attached if you want to verify.
Header:
#import <UIKit/UIKit.h>
#interface ClientFinder_ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate,NSNetServiceBrowserDelegate>
#property (weak, nonatomic) IBOutlet UITableView *availableClientsTableView;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict;
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
-(void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
#end
Relevant Implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
dictionaryFoundClients = [[NSMutableDictionary alloc] initWithCapacity:1];
[self addLogoToNabar];
[self listen];
}
-(void)listen{
NSNetServiceBrowser *serviceBrowser = [NSNetServiceBrowser new];
[serviceBrowser setDelegate:self];
[self.netServiceBrowser searchForServicesOfType:TYPE inDomain:domain];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing{
NSLog(#"aNetServiceBrowser didFindDomain");
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
NSLog(#"aNetServiceBrowser didFindService");
[dictionaryFoundClients setObject:aNetService forKey:aNetService.hostName];
NSLog(#"Found service: %# # %#", aNetService.name, aNetService.hostName);
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict{
NSLog(#"aNetServiceBrowser didNotSearch. Errors enumerated");
for(int a=0; a< errorDict.count; a++){
NSString *key = [[errorDict allKeys] objectAtIndex:a];
NSString *val = [errorDict objectForKey:key];
NSLog(#"%#: %#", key, val);
}
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"netServiceBrowserDidStopSearch");
}
-(void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"netServiceBrowserWillSearch");
}

If this is all local, you need to use searchForServicesOfType: method instead of searchForRegistrationDomains method.
-(void)listen{
NSNetServiceBrowser *serviceBrowser = [NSNetServiceBrowser new];
[serviceBrowser setDelegate:self];
[serviceBrowser searchForServicesOfType:#"_your_service_type._tcp" inDomain:#""];;
}
"_your_service_type._tcp" is the service type your desktop application is using when it advertises its service.

Not sure why it started working, but here is my working code:
[self stopCurrentResolve];
[self.netServiceBrowser stop];
[self.services removeAllObjects];
NSNetServiceBrowser *aNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
if(!aNetServiceBrowser) {
// The NSNetServiceBrowser couldn't be allocated and initialized.
return NO;
}
aNetServiceBrowser.delegate = self;
self.netServiceBrowser = aNetServiceBrowser;
[self.netServiceBrowser searchForServicesOfType:type inDomain:domain];

Related

Resolving NSNetService on server side

I have the problem in resolving NSNetService. i have successfully resolved NSNetService when NSNetServiceBrowser find that service.
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
if (![self.services containsObject:aNetService]) {
[aNetService setDelegate:self];
[aNetService resolveWithTimeout:5.0];
}
}
then this method is successfully called
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
NSArray *addresses = [ns addresses];
NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[sender TXTRecordData]];
// Here both values are ok
}
but i want to resolve NSNetService to server side to get the IP address on which that service is published.
-(void)netServiceDidPublish:(NSNetService *)ns{
[ns setDelegate:self];
[ns resolveWithTimeout:5.0];
}
but here this method is not calling.
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
 
}
however i did this
-(void)netServiceDidPublish:(NSNetService *)ns
{
NSArray *addresses = [ns addresses]; // this gives null
// this also gives null
NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[sender TXTRecordData]];
}
but values are null.
please help me if it is possible. any help will be appreciated. thanks in advance.
Had this problem the other day as well, and took me a while to figure it out.
For some reason, I needed to assign aNetService to a property.
# Declare a NSNetService property in the .h or further up .m file
#property (strong, nonatomic) NSNetService *currentService;
# In the .m file.
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
if (![self.services containsObject:aNetService]) {
self.currentService = aNetService;
[self.currentService setDelegate:self];
[self.currentService resolveWithTimeout:5.0];
}
}

Record and send/stream sound from iOS device to a server continuously

I am developing an iOS app that has a button with a microphone on it (along with other features). When the user presses the microphone, it gets highlighted and the app should now start recording sound from the device´s microphone and send to a server (a server dedicated to the app, developed by people that I know, so I can affect its design).
I am looking for the simplest yet sturdiest approach to do this, i.e. I have no need to develop a complicated streaming solution or VoIP functionality, unless it is as simple to do as anything else.
The main problem is that we have no idea for how long the user will be recording sound, but we want to make sure that sounds are sent to the server continuously, we do not wish to wait until the user has finished recording. It is okay if the data arrives to the server in chunks however we do not wish to miss any information that the user may be recording, so one chunk must continue where the previous one ended and so on.
Our first thought was to create "chunks" of sound clips of for example 10 seconds and send them continuously to the server. Is there any streaming solution that is better/simpler that I am missing out on?
My question is, what would be the most simple but still reliable approach on solving this task on iOS?
Is there a way to extract chunks of sound from a running recording by AVAudioRecorder, without actually stopping the recording?
look at this
in this tutorial, the sound recorded will be saved at soundFileURL, then you will just have to create an nsdata with that content, and then send it to your server.
hope this helped.
EDIT :
I just created a version that contain 3 buttons, REC, SEND and Stop :
REC : will start recording into a file.
SEND : will save what was recorded on that file in a NSData, and send it to a server, then will restart recording.
and STOP : will stop recording.
here is the code :
in your .h file :
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController <AVAudioRecorderDelegate>
#property (nonatomic, retain) AVAudioRecorder *audioRecorder;
#property (nonatomic, retain) IBOutlet UIButton *recordButton;
#property (nonatomic, retain) IBOutlet UIButton *stopButton;
#property (nonatomic, retain) IBOutlet UIButton *sendButton;
#property BOOL stoped;
- (IBAction)startRec:(id)sender;
- (IBAction)sendToServer:(id)sender;
- (IBAction)stop:(id)sender;
#end
and in the .m file :
#import "ViewController.h"
#implementation ViewController
#synthesize audioRecorder;
#synthesize recordButton,sendButton,stopButton;
#synthesize stoped;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
sendButton.enabled = NO;
stopButton.enabled = NO;
stoped = YES;
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir
stringByAppendingPathComponent:#"tempsound.caf"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0],
AVSampleRateKey,
nil];
NSError *error = nil;
audioRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
settings:recordSettings
error:&error];
audioRecorder.delegate = self;
if (error)
{
NSLog(#"error: %#", [error localizedDescription]);
} else {
[audioRecorder prepareToRecord];
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (BOOL) sendAudioToServer :(NSData *)data {
NSData *d = [NSData dataWithData:data];
//now you'll just have to send that NSData to your server
return YES;
}
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
NSLog(#"stoped");
if (!stoped) {
NSData *data = [NSData dataWithContentsOfURL:recorder.url];
[self sendAudioToServer:data];
[recorder record];
NSLog(#"stoped sent and restarted");
}
}
- (IBAction)startRec:(id)sender {
if (!audioRecorder.recording)
{
sendButton.enabled = YES;
stopButton.enabled = YES;
[audioRecorder record];
}
}
- (IBAction)sendToServer:(id)sender {
stoped = NO;
[audioRecorder stop];
}
- (IBAction)stop:(id)sender {
stopButton.enabled = NO;
sendButton.enabled = NO;
recordButton.enabled = YES;
stoped = YES;
if (audioRecorder.recording)
{
[audioRecorder stop];
}
}
#end
Good Luck.
It might actually be easier to have fixed-size chunks, instead of fixed-time. Then you can have two buffers, one that you currently fill with sample data. When the active buffer is full, then switch to fill the other buffer, while sending a signal to a sender-thread that takes the first buffer and sends it to the server.
You can of course use fixed-time instead, but then you need to make sure that the buffer is large enough to keep all samples, or use a dynamic buffer that can increase in size when needed. The double-buffering and sending thread can still be the same though.

NSURL becomes null when passed as a parameter iphone

I have set up a couple of very simple methods that play with NSURLs and NSStrings.
the first method that gets called is getAudio. I want to set the variable audioPath equal to cleanAudio so that it can be used later in the encryptWithAudioFile. The problem is somewhere along the way when it is being passed as a parameter the object becomes null. I have no idea why and I have tried every method I can think of in terms of memory management to try and keep the object. The logs I have used work result as follows
NSLog(#"Clean Audio1: %#", audioPath); Perfect, works as it should NSLog(#"Clean Audio2: %#", audioPath); NSLog(#"Clean Audio3: %#", audioPath); NSLog(#"Clean Audio4: %#", audioPath);
#implementation Stub
#synthesize audioPath,
userText;
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio{
self.audioPath = cleanAudio;
NSLog(#"Clean Audio1: %#", audioPath);
return cleanAudio;
}
-(NSString *)retrieveText:(NSString *)message{
self.userText = message;
NSLog(#"Text: %#", self.userText);
NSLog(#"Clean Audio2: %#", audioPath);
return message;
}
-(void)startEncrption{
NSLog(#"Clean Audio3: %#", self.audioPath);
[self encrypterWithAudioFile:self.audioPath withString:self.userText];
}
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text{
NSLog(#"DIRTY AUDIO and TEXT: %#, %#", audio, text);
return audio;
}
-(void)dealloc{
[super dealloc];
[audioPath release];
[userText release];
}
#end
Edit: Here's the .h
#interface Stub : NSObject {
NSURL *audioPath;
NSString *userText;
}
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio;
-(NSString *)retrieveText:(NSString *)message;
-(void)startEncrption;
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text;
#property(nonatomic, retain) NSURL *audioPath;
#property(nonatomic, retain) NSString *userText;
I'm calling the methods in other classes as follows:
stubObj = [[Stub alloc] init];
[stubObj retrieveAudio:recordedTmpFile];
and
stubObj2 = [[Stub alloc] init];
[stubObj2 retrieveText:textView.text];
[stubObj2 startEncrption];
Edit: I should probably have mentioned that I have three views, all with different controllers running on a UIScrollView that are calling the [Stub] interface.
I would look into your memory management and make sure you are not over releasing that URL some where after you've passed it into this methods. What I can see from your current code is that (assuming your audioPath property is marked retain) you are actually over retaining it within this snipped when you are assigning it:
self.audioPath = [[NSURL alloc] initWithString:#"TEST"];
Should be:
self.audioPath = [NSURL urlWithString:#"TEST"];
It looks as if you are allocating the NSURL only in -[Stub getAudio:], right? It also looks like you are creating multiple Stub objects. Are you calling the getAudio: method on each of those objects before trying to use the audioPath property on that object? That could be your problem.
In your latest update of the post, you include 2 different examples of how you use this class. In the first one you have this:
stubObj = [[Stub alloc] init];
[stubObj retrieveAudio:recordedTmpFile];
I assume that this is working, and that your "Clean Audio1:" log shows the expected URL, is that correct?
In your next example you have this:
stubObj2 = [[Stub alloc] init];
[stubObj2 retrieveText:textView.text];
[stubObj2 startEncrption];
Since this is a new instance and you never call retrieveAudio on this instance, the audioPath property for this instance is never set so it is nil. When you call startEncrption it calls encrypterWithAudioFile and passes self.audioPath, which is nil. Isn't this what you are expecting or am I missing something here?
Finally figured out a fix. I ended up moving all my variables to my app delegate and referenced them from other classes by pointing to the delegate::
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
I removed the startEncryption method altogether and called the method encryptWithAudioFile like this:
[stubObj2 encrypterWithAudioFile:appDelegate.audioPath withString:appDelegate.userText];
My final code ended up looking like this:
#implementation Stub
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio{
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.audioPath = cleanAudio;
NSLog(#"Clean Audio (retrieveAudio): %#", appDelegate.audioPath);
return cleanAudio;
}
-(NSString *)retrieveText:(NSString *)message{
// self.audioPath = [NSURL URLWithString:#"TEST"];
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.userText = message;
NSLog(#"Text: %#", appDelegate.userText);
NSLog(#"Clean Audio (retireveText): %#", appDelegate.audioPath);
return message;
}
//-(void)startEncrption{
// NSLog(#"Clean Audio (startEncryption): %# TEXT: %#", self.audioPath, self.userText);
// //self.audioPath = [NSURL URLWithString:#"TEST"];
// [self encrypterWithAudioFile:self.audioPath withString:self.userText];
//
//}
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text{
NSLog(#"DIRTY AUDIO and TEXT: %#, %#", audio, text);
return audio;
}
-(void)dealloc{
[super dealloc];
}
#end
I know there are still some memory management issues with this but its working finally so I can figured that out myself. Thanks for all your help.

Referencing superview's methods

I'm making an application in Xcode, and running into some problems. I'm using the GameKit framework to allow for bluetooth communication between two iOS devices. The application is setup so that one of the devices is the "master" and the other is the "slave," changing it's screen content based on data received from the "master" device. The user can select whether to be the master or the slave, and when that choice is made, the other device automatically becomes the opposite role. This is all done in one view controller class. When a role is chosen, a subview is added to the baseViewController.
What my problem is, is that when the subview that is added, I would like to be able to send data using the methods in the baseViewController class. With the current setup, the device invoking the action becomeMaster:sender crashes.
What I've tried so far is,
BaseViewController:
-(IBAction)becomeMaster:(id)sender {
[self dataToSend:#"slave"]; //tells peer device to become slave, since this device is master
masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[masterViewController setBaseViewController:self];
[self.view addSubview:masterViewController.view];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
//----------------------------------------------------------------------------//
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
//—-convert the NSData to NSString—-
NSString* str;
str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self useReceivedData:str];
[str release];
}
-(void)useReceivedData:(NSString *)str {
if ([str isEqualToString:#"forward"]) {
[slaveViewController.view setBackgroundColor:[UIColor blackColor]];
}
}
MasterViewController:
-(void)setBaseViewController:(BaseViewController *)bvc {
baseViewController = bvc;
}
-(IBAction)goForward:(id)sender {
actionLabel.text = #"goingForward";
[baseViewController dataToSend:#"forward"];
}
Most of that code is part of the standard Apple documentation/examples, but I included it for understanding the flow of logic.
I believe the problem originates to with the becomeMaster:sender and setBaseViewController:bvc methods. Could anyone help fix? Thanks so much!
What kind of crash are you getting? EXC_BAD_ACCESS? Try turning on NSZombieEnabled in your executable's arguments. It's difficult to say what could be causing the crash, but you might try changing your setBaseViewController: implementation to this:
-(void)setBaseViewController:(BaseViewController *)bvc {
[self willChangeValueForKey:#"baseViewController"];
[baseViewController autorelease]
baseViewController = [bvc retain];
[self didChangeValueForKey:#"baseViewController"];
}
And add [baseViewController release]; to MasterViewController's -dealloc method.
Keep in mind that it's not entirely necessary to have a custom setter for baseViewController. If you have the following property declaration in your header file:
#property (nonatomic, retain) BaseViewController *baseViewController;
And you use #synthesize baseViewController, the -setBaseViewController: method is already generated for you, with key-value observing support built in. If you aren't familiar with Objective-C 2.0 properties, I suggest reading Apple's documentation.

iPhone - Objective-C - Memory Leak with initWithArray

I am using the code below to set my two NSArray ivars:
The issue is, I keep getting a memory leak on the following lines:
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
Is this not the correct way to set ivars from an existing NSArray of items? Any help would be appreciated. I've also tried to autorelease the above two lines, but when I actually access them in another method I get an error that they've already been released.
I have included my Interface and Implementation code below:
Interface .h:
NSArray *followingFriendsArray;
NSArray *followerFriendsArray;
#property (nonatomic, retain) NSArray *followingFriendsArray;
#property (nonatomic, retain) NSArray *followerFriendsArray;
Implementation .m:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
This is how I need to access the arrays:
- (void)followersButtonTapped:(id)sender {
FollowingVC *fvc = [[FollowingVC alloc] initWithNibName:#"FollowingViewController" bundle:nil];
fvc.friends = followerFriendsArray;
[self.navigationController pushViewController:fvc animated:YES];
[fvc release];
}
I release my two ivars in the following way as per usual:
- (void)viewDidUnload {
self.followingFriendsArray = nil;
self.followerFriendsArray = nil;
[super viewDidUnload];
}
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
I mean the code works just fine, it's just that I'm concerned about said memory leaks when I run the "Leaks" performance tool.
OK
you should not use autorelease in this case, but you have to release the arrays by calling :
[followingFriendsArray release];
[followerFriendsArray release];
you can do it:
when you don't need to use them any more.
in the dealloc method in your .m file.
option 2looks like that -
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
BTW -
if you don't manipulate the arrays after creating them (add / remove objects) you should use an immutable array (NSArray).
Good Luck
Your method handlerGetFollowingInformation is assigning new values to followingFriendsArray and followerFriendsArray without releasing the previous contents. If you call this method more than once on the same instance you will leak.
CRD is right that the arrays are not released inside the handlerGeFollowingInformation method but the fix is maybe overkill. What you need to do is to use self. so that the setter method is called which does that automatically. You could should look like this:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
self.followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
self.followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
Easy fix but hard to spot and I ran into this issue over and over again especially when I started to dealloc are the properties.
-Andy