Stopping a `CallbackInstrument` prior to setting `AVAudioSession.setActive(false)` - swift

In attempt to pause my signal chain when a user puts the app into the background, or is interrupted by a phone call, I am trying to handle the interruption by stopping all playing nodes and setting the AVAudioSession().setActive(false) as per convention.
It seems fine to call stop() on all nodes except CallbackInstrument, which crashes at line 231 of DSPBase.cpp in *CAudioKitEX from the AudioKitEX repo :
void DSPBase::processOrBypass(AUAudioFrameCount frameCount, AUAudioFrameCount bufferOffset) {
if (isStarted) {
process(FrameRange{bufferOffset, frameCount});
} else {
// Advance all ramps.
stepRampsBy(frameCount);
// Copy input to output.
if (inputBufferLists.size() and !bCanProcessInPlace) {
for (int channel=0; channel< channelCount; ++channel) {
auto input = (const float *)inputBufferLists[0]->mBuffers[channel].mData + bufferOffset;
auto output = (float *)outputBufferList->mBuffers[channel].mData + bufferOffset;
std::copy(input, input+frameCount, output);
}
}
// Generators should be silent.
if (inputBufferLists.empty()) {
zeroOutput(frameCount, bufferOffset);
}
}
}
My CallbackInstrument is attached to a Sequencer as a discrete track. The crash occurs when the sequencer is playing and the app goes into the background, which I then call a method to stop all current sequencers, stop all active nodes prior to calling AVAudioSession.setSession(false).
I would simply ignore this and/or not stop CallbackInstrument however, by not attempting to stop or reset the CallbackInstrument node, AVAudioSession catches an error:
AVAudioSession_iOS.mm:1271 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
Error seting audio session false:Error Domain=NSOSStatusErrorDomain Code=560030580 "(null)"
Error code=560030580 refers to AVAudioSessionErrorCodeIsBusy as stated here
Question:
If stopping a Sequencer with a CallbackInstrument does not in fact stop rendering audio/midi from the callback, how do we safely stop a signal chain with a CallbackInstrument in order to prepare for AVAudioSession.setActive(false)?
I have an example repo of the issue which can be found here.

Nicely presented question by the way :)
Seems like doing it this way does not guarantee that the audioBufferList in process or bypass is populated, while it does report that the size() == 1, its pointer to audioBuferList[0] is nill...
Possibly there should be an additional check for this?
However, if instead of calling stop() on every node in your AudioManager.sleep() if you call engine.stop()
and conversely self.start() in your AudioManager.wake() instead of start on all your nodes... This avoids your error and should stop/start all nodes in the process.

Related

Signal is always caught by parent process first

Consider the following piece of code running under Solaris 11.3 (a simplified version of system(3C)):
int main(int argc, char **argv) {
pid_t pid = fork();
pid_t w;
int status;
if (pid == 0) {
execvp(argv[1], argv + 1);
perror("Failed to exec");
exit(127);
}
if (pid > 0) {
w = waitpid(pid, &status, 0);
if (w == -1) {
perror("Wait: ");
exit(1);
}
else if (WIFEXITED(status) > 0) {
printf("\nFinish code: %d\n", WEXITSTATUS(status));
}
else {
printf("\nUnexpected termination of child process.\n");
}
}
if (pid == -1) {
perror("Failed to fork");
}
}
The problem I get is that whenever the process is finished via a signal (for instance, SIGINT) the "Unexpected termination" message is never printed.
The way I see it, the whole process group receives signals from the terminal, and in this case the parent process simply terminates before waitpid(2) returns (Which happens every time, apparently).
If that is the case, I have a follow-up question. How to retrieve infromation about the signal that terminated the child process from the parent without using a signal handler? For example, I could have added another if-else block with a WIFSIGNALED check and a WTERMSIG call passing the variable status (In fact, I did, but upon termination with Ctrl+C the program delivered no output whatsoever)
So what exactly and in which order is happening there?
You say, “… whenever the process is finished via a signal
(for instance, SIGINT) …”, but you aren’t specific enough
to enable anybody to answer your question definitively. 
If you are sending a signal to the child process with a kill command,
you have an odd problem. 
But if, as I suspect (and as you suggest when you say
“the whole process group receives signals from the terminal”),
you are just typing Ctrl+C, it’s simple:
When you type an INTR, QUIT, or SUSP character,
the corresponding signal (SIGINT, SIGQUIT, or SIGTSTP) is sent
simultaneously to all processes in the terminal process group.
OK, strictly speaking, it’s not simultaneous. 
It happens in a loop in the terminal driver
(specifically, I believe, the “line discipline” handler), in the kernel. 
No user process execution can occur before this loop completes.
You say “… the parent process simply terminates
before waitpid(2) returns (… every time, apparently).” 
Technically this is true. 
As described above, all processes in the process group
(including your parent and child processes) receive the signal
(essentially) simultaneously. 
Since the parent is not handling the signal, itself,
it terminates before it can possibly do any processing
triggered by the child’s receipt of the signal.
You say “Signal is always caught by parent process first”. 
No; see above. 
And the processes terminate in an unspecified order —
this may be the order in which they appear in the process table
(which is indeterminate),
or determined by some subtle (and, perhaps, undocumented) aspect
of the scheduler’s algorithm.
Related U&L questions:
What is the purpose of abstractions, session, session leader
and process groups?
What are the responsibilities of each Pseudo-Terminal (PTY) component
(software, master side, slave side)?
Does it work ok if you send signals via a "kill" from another tty? I tried this on linux. Seems the same behavior.
I think you're right if that shell control signals are passed to the process group....and you have a race. You need in the parent to catch and delay them.
What I've done is do "./prog cat"
Doing a kill -SIGINT
works fine.
Doing a control-C prints nothing.
Doing a setsid() in front has the parent terminate, but the child keep running.

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.