Speakhere does NOT record after receive a phone call - iphone

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

Related

TestFlight TFLog not uploading when there is a crash

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

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.

FMOD and simple If statement

I have a simple set of FMOD actions that each play various sounds separately. The problem comes in that I have a button that stops all the sounds. FMOD crashes my program if we try to stop a sound that isn't playing. Makes sense. But I've decided that there has to be a way to call a simple if statement to find out "if" and only "if" somethings playing, then stop it.
- (IBAction)myButton:(id)sender {
if "FMOD CHANNEL IS PLAYING" {
result = fmodChannel->stop();
}
}
Any help would be appreciated.
I wouldn't say it “makes sense” that FMOD crashes if you call stop on a channel that isn't playing. It's documented to return an error code on failure. Are you sure fmodChannel is still a valid pointer when you call stop?
Anyway, you can try the isPlaying method:
bool isPlaying;
if (fmodChannel->isPlaying(&isPlaying) == FMOD_OK && isPlaying) {
fmodChannel->stop();
}

NSStream Event Timer - iPhone

All,
Is there a way to have a minimum time to keep a stream open before it closes? For some reason, my stream is closing prematurely which is causing errors elsewhere. I need to keep it open to make sure ALL of the data is gathered, and then it can run the other code.
Thanks,
James
In the case that someone falls upon this question later, I ended up creating nested if statements to pull it off.
Basically, there is one statement that checks if the end tag is not found (for my code, the END of the ENTIRE data that I should be receiving is </SessionData> - So, I did if([outputString rangeOfString:#"</SessionData>"].location == NSNotFound). I created a string called totalOutput that would have the outputString added onto the end of totalOutput until the </SessionData> is found.
If anyone ever needs help, just go ahead and comment on here and I can give more information.

WMI and Win32_DeviceChangeEvent - Wrong event type returned?

I am trying to register to a "Device added/ Device removed" event using WMI. When I say device - I mean something in the lines of a Disk-On-Key or any other device that has files on it which I can access...
I am registering to the event, and the event is raised, but the EventType propery is different from the one I am expecting to see.
The documentation (MSDN) states : 1- config change, 2- Device added, 3-Device removed 4- Docking. For some reason I always get a value of 1.
Any ideas ?
Here's sample code :
public class WMIReceiveEvent
{
public WMIReceiveEvent()
{
try
{
WqlEventQuery query = new WqlEventQuery(
"SELECT * FROM Win32_DeviceChangeEvent");
ManagementEventWatcher watcher = new ManagementEventWatcher(query);
Console.WriteLine("Waiting for an event...");
watcher.EventArrived +=
new EventArrivedEventHandler(
HandleEvent);
// Start listening for events
watcher.Start();
// Do something while waiting for events
System.Threading.Thread.Sleep(10000);
// Stop listening for events
watcher.Stop();
return;
}
catch(ManagementException err)
{
MessageBox.Show("An error occurred while trying to receive an event: " + err.Message);
}
}
private void HandleEvent(object sender,
EventArrivedEventArgs e)
{
Console.WriteLine(e.NewEvent.GetPropertyValue["EventType"]);
}
public static void Main()
{
WMIReceiveEvent receiveEvent = new WMIReceiveEvent();
return;
}
}
Well, I couldn't find the code. Tried on my old RAC account, nothing. Nothing in my old backups. Go figure. But I tried to work out how I did it, and I think this is the correct sequence (I based a lot of it on this article):
Get all drive letters and cache
them.
Wait for the WM_DEVICECHANGE
message, and start a timer with a
timeout of 1 second (this is done to
avoid a lot of spurious
WM_DEVICECHANGE messages that start
as start as soon as you insert the
USB key/other device and only end
when the drive is "settled").
Compare the drive letters with the
old cache and detect the new ones.
Get device information for those.
I know there are other methods, but that proved to be the only one that would work consistently in different versions of windows, and we needed that as my client used the ActiveX control on a webpage that uploaded images from any kind of device you inserted (I think they produced some kind of printing kiosk).
Oh! Yup, I've been through that, but using the raw Windows API calls some time ago, while developing an ActiveX control that detected the insertion of any kind of media. I'll try to unearth the code from my backups and see if I can tell you how I solved it. I'll subscribe to the RSS just in case somebody gets there first.
Well,
u can try win32_logical disk class and bind it to the __Instancecreationevent.
You can easily get the required info
I tried this on my system and I eventually get the right code. It just takes a while. I get a dozen or so events, and one of them is the device connect code.