TestFlight TFLog not uploading when there is a crash - iphone

When TestFlight crashes I have a log I wish to upload with its crash report.
Following the instructions on their website I came up with this solution, but it doesn't seem to be sending the log I pass to TFLog. However it reports the crash just fine.
-(void)applicationDidFinishLaunching:(UIApplication *)application {
/*Setup crash handlers for TestFlight so we can send logs. */
NSSetUncaughtExceptionHandler(&testFlightHandleExceptions);
// create the signal action structure
struct sigaction newSignalAction;
// initialize the signal action structure
memset(&newSignalAction, 0, sizeof(newSignalAction));
// set SignalHandler as the handler in the signal action structure
newSignalAction.sa_handler = &testFlightSignalHandler;
// set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS
sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL);
[TestFlight takeOff:TESTFLIGHT_API_KEY];
}
void testFlightHandleExceptions(NSException *exception) {
[LogManager e: #"Sending crash to TestFlight" Tag:#"AppDelegate"];
TFLog(#"%#",[LogManager getLog]);
}
Where have I gone wrong? Or is there a better way in doing this?

There are two problems I can see with this:
testFlightHandleExceptions is going to be called after the crash and it's logs are recorded. Instead you need to be calling TFLog inside of LogManager every time you log something (before the crash). That's how it's meant to be used.
It is not ok to use objc inside of a signal handler. For that matter, most c isn't even allowed.
Hope that helps :)
Jason

Related

Gstreamer 1.0 Pause signal

I need to detect when the current playing audio/video is paused. I cannot find anything for 1.0. My app is a bit complex but here is condensed code
/* This function is called when the pipeline changes states. We use it to
* keep track of the current state. */
static void state_changed_cb(GstBus *bus, GstMessage *msg, CustomData *data)
{
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
if(GST_MESSAGE_SRC(msg) == GST_OBJECT(data->playbin))
{
g_print("State set to %s\n", gst_element_state_get_name(new_state));
}
}
gst_init(&wxTheApp->argc, &argv);
m_playbin = gst_element_factory_make("playbin", "playbin");
if(!m_playbin)
{
g_printerr("Not all elements could be created.\n");
exit(1);
}
CustomData* data = new CustomData(xid, m_playbin);
GstBus *bus = gst_element_get_bus(m_playbin);
gst_bus_set_sync_handler(bus, (GstBusSyncHandler) create_window, data, NULL);//here I do video overly stuffs
g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, &data);
What do I do wrong? I cannot find working example on connecting such events on Gstreamer 1.0 and 0.x seems a bit different than 1.0 so the vast exaples there don't help
UPDATE
I have found a way to get signals. I run wxWidgets timer with 500ms time span and each time timer fires I call
GstMessage* msg = gst_bus_pop(m_bus);
if(msg!=NULL)
{
g_print ("New Message -- %s\n", gst_message_type_get_name(msg->type));
}
Now I get a lot of 'state-change' messages. Still I want to know if that message is for Pause or Stop or Play or End of Media (I mean way to differentiate which message is this) so that I can notify the UI.
So while I get signals now, the basic problem, to get specific signals, remains unsolved.
You have to call gst_bus_add_signal_watch() (like in 0.10) to enable emission of the signals. Without that you can only use the other ways to get notified about GstMessages on that bus.
Also just to be sure, you need a running GLib main loop on the default main context for this to work. Otherwise you need to do things a bit different.
For the updated question:
Check the documentation: gst_message_parse_state_changed() can be used to parse the old, new and pending state from the message. This is also still the same as in 0.10. From the application point of view, and conceptionally nothing much has changed really between 0.10 and 1.0
Also you shouldn't do this timeout-waiting as it will block your wxwidget main loop. Easiest solution would be to use a sync bus handler (which you already have) and dispatch all messages from there to some callback on the wxwidget main loop.

AudioQueue PropertyListener IsRunning only callback once

OSStatus err = AudioQueueNewOutput(&audioDescription, AudioPlayerAQOutputCallback, ( void* )self, nil, nil, 0, &audioQueue);
if( err != noErr )
NSLog(#"Couldn't open AudioFile.");
err = AudioQueueAddPropertyListener(audioQueue, kAudioQueueProperty_IsRunning, isRunningProc, self);
if( err != noErr )
NSLog(#"Couldn't register for playback state changes.");
this callback function only be called once after AudioQueueStart(audioQueue, NULL);
what ever i call AudioQueuePause(audioQueue);
or audio reach to end.
static void isRunningProc(void * inUserData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID)
what i have missed?
I did a short test on this:
It does indeed seem like the callback it is not called either for pause or for start, when you are resuming a pause.
But this is not something you cannot solve. You started the song somehow. This will trigger the property listener. Equally if the song stops. Or you stop it. You may have to trigger the property listener yourself somehow using something like this in your play routine:
if (bytesRead == 0) {
//This will trigger the property listener
AudioQueueStop(inAQ, false);
}
else {
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
}
As AudioQueue is concerned, as long as you keep feeding it with audio buffers to play, it is still playing. (I also tested not feeding any buffers at all, which did not trigger a stop, so you have to call stop explicitly to trigger the property listener.)
This means you already know whether your song is playing or not. To pause or un-pause is requested by clicking your button. If the song is not playing, don't do anything. If the song is playing, call AudioQueuePause and set a flag that you have paused your music. Remember to check the error code. (See (1) below). If the flag says that you have paused the music, call AudioQueueStart, and clear the flag indicating if you have paused or not. Again check the error code.
(1) Why check the error code?
First, although unlikely, an error may occur because it is a blue moon.
However, my concern is with multiple threads. AudioQueue obviously runs on a separate thread than your GUI. That means if you test a flag whether music is playing or not, this state cannot fully be trusted because it might have changed since you tested the status. Another thread might have snuck in between your test and your action based on that test.
Say you check that the song is already playing. (It is.)
Then you ask the song to pause, but the song is really stopped since it reached the end in the meantime before you got to ask the song to pause.
Then you ask to pause the song. But it is already stopped.
What happens then? I don't really know. It might not even be a problem in this situation, but things like this is worth considering. It needs testing, or at least a consulting with the documentation.
How about another scenario? What if the song is stopped and you ask to start it again. I would think that is a worse scenario, but it might not be a problem. Again consider those cases and check the documentation, or even test yourself.

Speakhere does NOT record after receive a phone call

I'm working on a project that need record and analyze sound, every think is ok when i use speak here.
But when some one call my phone, the record stop and when the app return, it never record again.
I try to restart the recorder by press record, but i get this error:
Error: couldn't get input channel count ('!cat')
Error: couldn't enable metering (-50)
ERROR: metering failed
I also try to restart by call StartRecord(....) but nothing different. So anyone can help me
if (inInterruptionState == kAudioSessionEndInterruption)
THIS->recorder->StartRecord(CFSTR("recordedFile.caf"));
An app must stop recording in any audio session interrupt listener begin interruption callback if it ever wants to start recording again. Otherwise, a force quit and restart by the user may be required.
I've been having the same problem with SpeakHere and found this solution by (hours and hours of) trial and error. Try this: get rid of the references to playbackWasInterrupted (commented out below), but leave in the other player-related directives. Somehow this re-enables the recorder! If anyone could explain why this works, I would love to know!
Under void interruptionListener, change
else if ((inInterruptionState == kAudioSessionEndInterruption)&& THIS->playbackWasInterrupted))
to
else if (inInterruptionState == kAudioSessionEndInterruption)
//&& THIS->playbackWasInterrupted)
and then comment out or delete the "playbackWasInterrupted" line below:
{
// we were playing back when we were interrupted, so reset and resume now
THIS->player->StartQueue(true);
[[NSNotificationCenter defaultCenter] postNotificationName:#"playbackQueueResumed" object:THIS];
// THIS->playbackWasInterrupted = NO;
}
just from memory - when returning to foreground (in the corresponding notification handler), you need to call
AudioSessionSetActive (true)
or something similar. As I said, I only read it on a related question - no garanties.
Good Luck, nobi

boost::asio::io_service::run() is not exiting when i call boost::asio::io_serive::stop()

Hi I having written one simple application which uses the asynchronous socket functions. I am facing some problems while closing the socket.
I am using 5 second timer before calling the async_connect on the socket. In some cases the connection is not happening and timer expires. When timer is expired I am closing the socket tcp_socket.close(). But the thing is my connection callback handler is not at all called with the boost::asio::error::operation_aborted error when i tried to cancel instead of close. The same thing is happening for the next all the async connection invokes.
Eventhough I am closing the tcp socket and destroying the client_session object join() call on the created thread is not coming out means io_service::run() is still running not exiting...:-( I don't know why this is happening... tried lot of other ways still facing the same problem.
I am not getting what is the problem, all suggestions and solutions will be appreciated.
My real code some what look like this.
class client_session
{
public:
client_session(boost::asio::io_service& io_service_ )tcp_socekt_(io_service_),
timer_(io_service_)
{
}
~client_session()
{
tcp_socket_.close();
}
void OnTimerExpired(const boost::system::error_code& err)
{
if( err ) tcp_socket_.close();
}
//Its just for example this will be called from upper layer of my module. giving some information about the server.
void connect()
{
//Here am starting the timer
timer_.expires_from_now(boost::posix_time::seconds(2));
timer_.async_wait(boost::bind(&OutgoingSession::OnTimerExpiry, this,PLACEHLDRS::error));
.......
tcp_socket_.async_connect(iterator->endpoint(), boost::bind( &OutgoingSession::handle_connect, this, _1, iterator));
......
}
void OnConnect(const boost::system::error_code& err)
{
//Cancelling the timer
timer_.cancel();
.....
//Register for write to send the request to server
......
}
private:
tcp::socket tcp_socket_;
deadline_timer timer_;
}
void main()
{
boost::asio::io_service tcp_io_service;
boost::asio::io_service::work tcp_work(tcp_io_service);
boost::thread* worker = new boost::thread(&boost::asio::io_service::run,&tcp_io_service);
client_session* csession = new client_session(tcp_io_service);
csession->connect();
sleep(10);
tcp_io_service.stop();
delete csession;
worker.join(); //Here it not coming out of join because io_service::run() is not exited yet.
cout<<"Termination successfull"<<endl;
}
There seem to be a couple of different things wrong with the posted code. I would suggest starting with smaller steps i.e. along the lines of
start and stop asio worker thread cleanly ( see explanation below )
add code to start timer: handle OnTimerExpired correctly, check error code
add in code for async_connect: when connect handler is called, cancel timer and check error code.
add in other asynchronous operations, etc.
For one, when you cancel the timer in the connect handler, the OnTimerExpired handler will be invoked with boost::asio::operation_aborted and then you close the socket, which is probably not what you want to do.
Further, you give the io_service work, yet still call stop. Generally if you give the io_service work, you want to stop the execution thread by removing the work (e.g. This can be accomplished by means of storing work in a smart pointer and resetting it) and letting the currently started asynchronous operations finish cleanly.

Confusion about CFNetwork, CFReadStreamOpen, and CFRunLoopRun

That sinking feeling when you realize you have no idea what's going on...
I've been using this code in my network code for almost two years without problems.
if (!CFReadStreamOpen(myReadStream)) {
CFStreamError myErr = CFReadStreamGetError(myReadStream);
if (myErr.error != 0) {
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
strerror(myErr.error);
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
OSStatus macError = (OSStatus)myErr.error;
}
// Check other domains.
}
}
I believe it was originally based on the code samples given here:
http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/CFStreamTasks.html
I recently noticed, however, that some connections are failing, because CFReadStreamOpen returns false but the error code is 0. After staring at the above link some more, I noticed the CFRunLoopRun() statement, and added it:
if (!CFReadStreamOpen(myReadStream)) {
CFStreamError myErr = CFReadStreamGetError(myReadStream);
if (myErr.error != 0) {
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
strerror(myErr.error);
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
OSStatus macError = (OSStatus)myErr.error;
}
// Check other domains.
} else
// start the run loop
CFRunLoopRun();
}
This fixed the connection problem. However, my app started showing random problems - interface sometimes not responsive, or not drawing, text fields not editable, that kind of stuff.
I've read up on CFReadStreamOpen and on run loops (specifically, that the main run loop runs by itself and I shouldn't run a run loop unless I'm setting it up myself in a secondary thread - which I'm not, as far as I know). But I'm still confused about what's actually happening above. Specifically:
1) Why does CFReadStreamOpen sometimes return FALSE and error code 0? What does that actually mean?
2) What does the CFRunLoopRun call actually do in the above code? Why does the sample code make that call - if this code is running in the main thread I shouldn't have to run the run loop?
I guess I'll answer my own question, as much as I can.
1) In my code, at least, CFReadStreamOpen always seems to return false. The documentation is a bit confusing, but I read it to mean the stream wasn't opened yet, but will be open later in the run loop.
2) Most of the calls I was making were happening in the main thread, where the run loop was already running, so calling CFRunLoopRun was unnecessary. The call that was giving me problems was happening inside a block, which apparently spawned a new thread. This new thread didn't start a new run loop - so the stream would never open unless I explicitly ran the new thread's run loop.
I'm still not 100% clear on what happens if I call CFRunLoopRun() on a thread with an already running run loop, but it's obviously not good.
I ended up ditching my home-brewed networking code and switching to ASIHTTPRequest, which I was considering to do anyway.