void GameProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) { // If something earlier failed, Connect() might still be called, but with a non-zero // error code. When that happens we simply unreserve the connection and do // nothing else. if (error) { fOutput.destination = media_destination::null; fOutput.format = fPreferredFormat; return; } // Okay, the connection has been confirmed. Record the destination and format // that we agreed on, and report our connection name again. fOutput.destination = destination; fOutput.format = format; strlcpy(io_name, fOutput.name, B_MEDIA_NAME_LENGTH); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(fOutput.destination, &fLatency, &id); if (!fBufferGroup) fBufferSize = fOutput.format.u.raw_audio.buffer_size; // Have to set it before latency calculating // Use a dry run to see how long it takes me to fill a buffer of data // The first step to setup the buffer bigtime_t start, produceLatency; int32 frames = int32(fBufferSize / fFrameSize); float* data = new float[frames * 2]; // Second, fill the buffer start = ::system_time(); for (int32 i = 0; i < frames; i++) { data[i*2] = 0.8 * float(i/frames); data[i*2+1] = 0.8 * float(i/frames); } produceLatency = ::system_time(); // Third, calculate the latency fInternalLatency = produceLatency - start; SetEventLatency(fLatency + fInternalLatency); // Finaily, clean up delete [] data; // reset our buffer duration, etc. to avoid later calculations bigtime_t duration = bigtime_t(1000000) * frames / bigtime_t(fOutput.format.u.raw_audio.frame_rate); SetBufferDuration(duration); // Set up the buffer group for our connection, as long as nobody handed us a // buffer group (via SetBufferGroup()) prior to this. if (!fBufferGroup) { int32 count = int32(fLatency / BufferDuration() + 2); fBufferGroup = new BBufferGroup(fBufferSize, count); } }
void ESDSinkNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) { CALLED(); node_output *channel = FindOutput(source); // is this our output? if (channel == NULL) { fprintf(stderr, "ESDSinkNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n"); return; } // If something earlier failed, Connect() might still be called, but with a non-zero // error code. When that happens we simply unreserve the connection and do // nothing else. if (error) { channel->fOutput.destination = media_destination::null; channel->fOutput.format = channel->fPreferredFormat; return; } // Okay, the connection has been confirmed. Record the destination and format // that we agreed on, and report our connection name again. channel->fOutput.destination = destination; channel->fOutput.format = format; strncpy(io_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); // reset our buffer duration, etc. to avoid later calculations bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000 / ( (channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * channel->fOutput.format.u.raw_audio.channel_count) / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100)); SetBufferDuration(duration); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(channel->fOutput.destination, &fLatency, &id); PRINT(("\tdownstream latency = %Ld\n", fLatency)); fInternalLatency = BufferDuration(); PRINT(("\tbuffer-filling took %Ld usec on this machine\n", fInternalLatency)); //SetEventLatency(fLatency + fInternalLatency); // Set up the buffer group for our connection, as long as nobody handed us a // buffer group (via SetBufferGroup()) prior to this. That can happen, for example, // if the consumer calls SetOutputBuffersFor() on us from within its Connected() // method. if (!channel->fBufferGroup) AllocateBuffers(*channel); // we are sure the thread is started StartThread(); }
void SoundPlayNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* name) { CALLED(); // is this our output? if (source != fOutput.source) { TRACE("SoundPlayNode::Connect returning\n"); return; } // If something earlier failed, Connect() might still be called, but with // a non-zero error code. When that happens we simply unreserve the // connection and do nothing else. if (error) { fOutput.destination = media_destination::null; fOutput.format.type = B_MEDIA_RAW_AUDIO; fOutput.format.u.raw_audio = media_multi_audio_format::wildcard; return; } // Okay, the connection has been confirmed. Record the destination and // format that we agreed on, and report our connection name again. fOutput.destination = destination; fOutput.format = format; strcpy(name, Name()); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(fOutput.destination, &fLatency, &id); TRACE("SoundPlayNode::Connect: downstream latency = %Ld\n", fLatency); // reset our buffer duration, etc. to avoid later calculations bigtime_t duration = ((fOutput.format.u.raw_audio.buffer_size * 1000000LL) / ((fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * fOutput.format.u.raw_audio.channel_count)) / (int32)fOutput.format.u.raw_audio.frame_rate; SetBufferDuration(duration); TRACE("SoundPlayNode::Connect: buffer duration is %Ld\n", duration); fInternalLatency = (3 * BufferDuration()) / 4; TRACE("SoundPlayNode::Connect: using %Ld as internal latency\n", fInternalLatency); SetEventLatency(fLatency + fInternalLatency); // Set up the buffer group for our connection, as long as nobody handed us // a buffer group (via SetBufferGroup()) prior to this. // That can happen, for example, if the consumer calls SetOutputBuffersFor() // on us from within its Connected() method. if (!fBufferGroup) AllocateBuffers(); }
void FlangerNode::Connect( status_t status, const media_source& source, const media_destination& destination, const media_format& format, char* pioName) { PRINT(("FlangerNode::Connect()\n")); status_t err; // connection failed? if(status < B_OK) { PRINT(("\tStatus: %s\n", strerror(status))); // 'unreserve' the output m_output.destination = media_destination::null; return; } // connection established: strncpy(pioName, m_output.name, B_MEDIA_NAME_LENGTH); m_output.destination = destination; m_format = format; // figure downstream latency media_node_id timeSource; err = FindLatencyFor(m_output.destination, &m_downstreamLatency, &timeSource); if(err < B_OK) { PRINT(("\t!!! FindLatencyFor(): %s\n", strerror(err))); } PRINT(("\tdownstream latency = %Ld\n", m_downstreamLatency)); // prepare the filter initFilter(); // figure processing time m_processingLatency = calcProcessingLatency(); PRINT(("\tprocessing latency = %Ld\n", m_processingLatency)); // store summed latency SetEventLatency(m_downstreamLatency + m_processingLatency); if(m_input.source != media_source::null) { // pass new latency upstream err = SendLatencyChange( m_input.source, m_input.destination, EventLatency() + SchedulingLatency()); if(err < B_OK) PRINT(("\t!!! SendLatencyChange(): %s\n", strerror(err))); } // cache buffer duration SetBufferDuration( buffer_duration( m_format.u.raw_audio)); }
void EqualizerNode::Connect(status_t status, const media_source &src, const media_destination &dst, const media_format &format, char* name) { if (status < B_OK) { fOutputMedia.destination = media_destination::null; return; } strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH); fOutputMedia.destination = dst; fFormat = format; media_node_id timeSource; FindLatencyFor(fOutputMedia.destination, &fDownstreamLatency, &timeSource); InitFilter(); fProcessLatency = GetFilterLatency(); SetEventLatency(fDownstreamLatency + fProcessLatency); if (fInputMedia.source != media_source::null) { SendLatencyChange(fInputMedia.source, fInputMedia.destination, EventLatency() + SchedulingLatency()); } bigtime_t duration = 0; int sample_size = (fFormat.u.raw_audio.format & 0xf) * fFormat.u.raw_audio.channel_count; if (fFormat.u.raw_audio.buffer_size > 0 && fFormat.u.raw_audio.frame_rate > 0 && sample_size > 0) { duration = (bigtime_t)(((fFormat.u.raw_audio.buffer_size / sample_size) / fFormat.u.raw_audio.frame_rate) * 1000000.0); } SetBufferDuration(duration); }
status_t ConsumerNode::Connected( const media_source & producer, const media_destination & where, const media_format & with_format, media_input * out_input) { out("ConsumerNode::Connected\n"); if (where != mInput.destination) return B_MEDIA_BAD_DESTINATION; // calculate my latency here, because it may depend on buffer sizes/durations, then // tell the BMediaEventLooper how early we need to get the buffers SetEventLatency(10 * 1000); //fixme /* reserve the connection */ mInput.source = producer; mInput.format = with_format; /* and publish it's name and connection info */ *out_input = mInput; #if 0 /* create the buffer group */ if (mBufferGroup == NULL) { create_own_buffer_group(); mBufferGroup = mOwnBufferGroup; } /* set the duration of the node's buffers */ int32 numBuffers; mBufferGroup->CountBuffers(&numBuffers); SetBufferDuration((1000000LL * numBuffers) / mOutput.format.u.raw_video.field_rate); #endif return B_OK; }
void AudioProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* _name) { TRACE("AudioProducer::Connect(%s)\n", strerror(error)); // If something earlier failed, Connect() might still be called, but with // a non-zero error code. When that happens we simply unreserve the // connection and do nothing else. if (error != B_OK) { fOutput.destination = media_destination::null; fOutput.format = fPreferredFormat; return; } // Okay, the connection has been confirmed. Record the destination and // format that we agreed on, and report our connection name again. fOutput.destination = destination; fOutput.format = format; strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH); // tell our audio supplier about the format if (fSupplier) { TRACE("AudioProducer::Connect() fSupplier->SetFormat()\n"); fSupplier->SetFormat(fOutput.format); } TRACE("AudioProducer::Connect() FindLatencyFor()\n"); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(fOutput.destination, &fLatency, &id); // Use a dry run to see how long it takes me to fill a buffer of data size_t sampleSize = fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; size_t samplesPerBuffer = fOutput.format.u.raw_audio.buffer_size / sampleSize; fInternalLatency = estimate_internal_latency(fOutput.format); if (!fLowLatency) fInternalLatency *= 32; SetEventLatency(fLatency + fInternalLatency); // reset our buffer duration, etc. to avoid later calculations bigtime_t duration = bigtime_t(1000000) * samplesPerBuffer / bigtime_t(fOutput.format.u.raw_audio.frame_rate * fOutput.format.u.raw_audio.channel_count); TRACE("AudioProducer::Connect() SetBufferDuration(%lld)\n", duration); SetBufferDuration(duration); TRACE("AudioProducer::Connect() _AllocateBuffers()\n"); // Set up the buffer group for our connection, as long as nobody handed // us a buffer group (via SetBufferGroup()) prior to this. That can // happen, for example, if the consumer calls SetOutputBuffersFor() on // us from within its Connected() method. if (fBufferGroup == NULL) _AllocateBuffers(fOutput.format); TRACE("AudioProducer::Connect() done\n"); }
void MediaReader::Connect( status_t error, const media_source & source, const media_destination & destination, const media_format & format, char * io_name) { CALLED(); if (error != B_OK) { PRINT("\t<- error already\n"); output.destination = media_destination::null; GetFormat(&output.format); return; } if (output.source != source) { PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); output.destination = media_destination::null; GetFormat(&output.format); return; } // record the agreed upon values output.destination = destination; output.format = format; strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); io_name[B_MEDIA_NAME_LENGTH-1] = '\0'; // determine our downstream latency media_node_id id; FindLatencyFor(output.destination, &fDownstreamLatency, &id); // compute the buffer period (must be done before setbuffergroup) fBufferPeriod = bigtime_t(1000 * 8000000 / 1024 * output.format.u.multistream.max_chunk_size / output.format.u.multistream.max_bit_rate); PRINT("\tmax chunk size = %ld, max bit rate = %f, buffer period = %lld\n", output.format.u.multistream.max_chunk_size, output.format.u.multistream.max_bit_rate,fBufferPeriod); // setup the buffers if they aren't setup yet if (fBufferGroup == 0) { status_t status = SetBufferGroup(output.source,0); if (status != B_OK) { PRINT("\t<- SetBufferGroup failed\n"); output.destination = media_destination::null; GetFormat(&output.format); return; } } SetBufferDuration(fBufferPeriod); if (GetCurrentFile() != 0) { bigtime_t start, end; // buffer group buffer size uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; BBuffer * buffer = 0; ssize_t bytesRead = 0; { // timed section start = TimeSource()->RealTime(); // first we try to use a real BBuffer buffer = fBufferGroup->RequestBuffer( output.format.u.multistream.max_chunk_size,fBufferPeriod); if (buffer != 0) { FillFileBuffer(buffer); } else { // didn't get a real BBuffer, try simulation by just a read from the disk bytesRead = GetCurrentFile()->Read( data, output.format.u.multistream.max_chunk_size); } end = TimeSource()->RealTime(); } bytesRead = buffer->SizeUsed(); delete data; if (buffer != 0) { buffer->Recycle(); } GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it fInternalLatency = end - start; PRINT("\tinternal latency from disk read = %lld\n", fInternalLatency); } else { fInternalLatency = 100; // just guess PRINT("\tinternal latency guessed = %lld\n", fInternalLatency); } SetEventLatency(fDownstreamLatency + fInternalLatency); // XXX: do anything else? }
void ToneProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) { FPRINTF(stderr, "ToneProducer::Connect\n"); // If something earlier failed, Connect() might still be called, but with a non-zero // error code. When that happens we simply unreserve the connection and do // nothing else. if (error) { mOutput.destination = media_destination::null; mOutput.format = mPreferredFormat; return; } // old workaround for format bug: Connect() receives the format data from the // input returned from BBufferConsumer::Connected(). // // char formatStr[256]; // string_for_format(format, formatStr, 255); // FPRINTF(stderr, "\trequested format: %s\n", formatStr); // if(format.type != B_MEDIA_RAW_AUDIO) { // // +++++ this is NOT proper behavior // // but it works // FPRINTF(stderr, "\tcorrupted format; falling back to last suggested format\n"); // format = mOutput.format; // } // // Okay, the connection has been confirmed. Record the destination and format // that we agreed on, and report our connection name again. mOutput.destination = destination; mOutput.format = format; strncpy(io_name, mOutput.name, B_MEDIA_NAME_LENGTH); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(mOutput.destination, &mLatency, &id); FPRINTF(stderr, "\tdownstream latency = %" B_PRIdBIGTIME "\n", mLatency); // Use a dry run to see how long it takes me to fill a buffer of data bigtime_t start, produceLatency; size_t samplesPerBuffer = mOutput.format.u.raw_audio.buffer_size / sizeof(float); size_t framesPerBuffer = samplesPerBuffer / mOutput.format.u.raw_audio.channel_count; float* data = new float[samplesPerBuffer]; mTheta = 0; start = ::system_time(); FillSineBuffer(data, framesPerBuffer, mOutput.format.u.raw_audio.channel_count==2); produceLatency = ::system_time(); mInternalLatency = produceLatency - start; // +++++ e.moon [13jun99]: fiddling with latency, ick mInternalLatency += 20000LL; delete [] data; FPRINTF(stderr, "\tbuffer-filling took %" B_PRIdBIGTIME " usec on this machine\n", mInternalLatency); SetEventLatency(mLatency + mInternalLatency); // reset our buffer duration, etc. to avoid later calculations // +++++ e.moon 11jun99: crashes w/ divide-by-zero when connecting to LoggingConsumer ASSERT(mOutput.format.u.raw_audio.frame_rate); bigtime_t duration = bigtime_t(1000000) * samplesPerBuffer / bigtime_t(mOutput.format.u.raw_audio.frame_rate); SetBufferDuration(duration); // Set up the buffer group for our connection, as long as nobody handed us a // buffer group (via SetBufferGroup()) prior to this. That can happen, for example, // if the consumer calls SetOutputBuffersFor() on us from within its Connected() // method. if (!mBufferGroup) AllocateBuffers(); }
void AudioFilterNode::Connect( status_t status, const media_source& source, const media_destination& destination, const media_format& format, char* ioName) { PRINT(("AudioFilterNode::Connect()\n")); status_t err; #if DEBUG char formatStr[256]; string_for_format(format, formatStr, 255); PRINT(("\tformat: %s\n", formatStr)); #endif // connection failed? if(status < B_OK) { PRINT(("\tCONNECTION FAILED: Status '%s'\n", strerror(status))); // 'unreserve' the output m_output.destination = media_destination::null; return; } // connection established: strncpy(ioName, m_output.name, B_MEDIA_NAME_LENGTH); m_output.destination = destination; // figure downstream latency media_node_id timeSource; err = FindLatencyFor(m_output.destination, &m_downstreamLatency, &timeSource); if(err < B_OK) { PRINT(("\t!!! FindLatencyFor(): %s\n", strerror(err))); } PRINT(("\tdownstream latency = %Ld\n", m_downstreamLatency)); // // prepare the filter // initFilter(); // // // figure processing time // m_processingLatency = calcProcessingLatency(); // PRINT(("\tprocessing latency = %Ld\n", m_processingLatency)); // // // store summed latency // SetEventLatency(m_downstreamLatency + m_processingLatency); // // if(m_input.source != media_source::null) { // // pass new latency upstream // err = SendLatencyChange( // m_input.source, // m_input.destination, // EventLatency() + SchedulingLatency()); // if(err < B_OK) // PRINT(("\t!!! SendLatencyChange(): %s\n", strerror(err))); // } // cache buffer duration SetBufferDuration( buffer_duration( m_output.format.u.raw_audio)); // [re-]initialize operation updateOperation(); // initialize buffer group if necessary updateBufferGroup(); }
void ClientNode::HandleEvent(const media_timed_event *event, bigtime_t late, bool realTimeEvent) { //printf("ClientNode::HandleEvent %d\n", event->type); switch (event->type) { case BTimedEventQueue::B_HANDLE_BUFFER: { printf("BTimedEventQueue::B_HANDLE_BUFFER\n"); break; } case BTimedEventQueue::B_START: { printf("BTimedEventQueue::B_START\n"); if (RunState() != B_STARTED) { fFramesSent = 0; fTime = TimeSource()->RealTime(); int period = (fOwner->GetOutputPorts()->CountItems())*3; fBufferGroup = new BBufferGroup(fFormat.u.raw_audio.buffer_size, period); if (fBufferGroup->InitCheck() != B_OK) printf("error\n"); bigtime_t start = ::system_time(); ComputeCycle(); bigtime_t produceLatency = ::system_time(); fProcessLatency = produceLatency - start; printf("Estimated latency is %Ld\n", fProcessLatency); JackPortList* outputPorts = fOwner->GetOutputPorts(); for (int i = 0; i < outputPorts->CountItems(); i++) { JackPort* port = outputPorts->ItemAt(i); port->CurrentBuffer()->Recycle(); } int sample_size = (fFormat.u.raw_audio.format & 0xf)* fFormat.u.raw_audio.channel_count; bigtime_t duration = bigtime_t(1000000) * fOwner->BufferSize() / bigtime_t(fFormat.u.raw_audio.frame_rate); SetBufferDuration(duration); SetEventLatency(fDownstreamLatency + fProcessLatency); _ScheduleOutputEvent(fTime); } break; } case BTimedEventQueue::B_STOP: { // stopped - don't process any more buffers, flush all buffers // from event queue EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); Stop(TimeSource()->Now(), true); NodeStopped(TimeSource()->Now()); break; } case BTimedEventQueue::B_DATA_STATUS: { break; } case NEW_BUFFER_EVENT: { ComputeCycle(); _DataAvailable(event->event_time); // Now we schedule the next event bigtime_t nextEvent = fTime + bigtime_t((1000000LL * fFramesSent) / (int32)fFormat.u.raw_audio.frame_rate)+EventLatency(); _ScheduleOutputEvent(nextEvent); break; } default: break; } }
void EMBeOutputNode::Connect(status_t error, const media_source& p_sSource, const media_destination& p_sDestination, const media_format& p_sFormat, char* p_vpName) { /* if (error) { m_sOutput.destination = media_destination::null; m_sOutput.format = m_sPreferredOutputFormat; return; } media_output* spDesiredOutput = NULL; if(m_sOutput.source == p_sSource) spDesiredOutput = &m_sOutput; else return; spDesiredOutput -> destination = media_destination::null; spDesiredOutput -> destination = p_sDestination; spDesiredOutput -> format = p_sFormat; strncpy(p_vpName, Name(), B_MEDIA_NAME_LENGTH); media_node_id id; FindLatencyFor(m_sOutput.destination, &mLatency, &id); mInternalLatency = 12000; BMediaEventLooper::SetEventLatency(mLatency + mInternalLatency); int64 vDuration = EMBeMediaUtility::FramesToTime(EMBeMediaUtility::FramesPerBuffer(GetConnectedEMMediaFormat()), GetConnectedEMMediaFormat()); if(vDuration < 0) vDuration = 40000; GetConnectedEMMediaFormat() -> Display(); SetBufferDuration(vDuration); */ // If something earlier failed, Connect() might still be called, but with a non-zero // error code. When that happens we simply unreserve the connection and do // nothing else. // if (error) // { // m_sOutput.destination = media_destination::null; // m_sOutput.format = m_sPreferredOutputFormat; // return; // } // Okay, the connection has been confirmed. Record the destination and format // that we agreed on, and report our connection name again. memcpy(&(m_sOutput.destination), &p_sDestination, sizeof(media_destination)); memcpy(&(m_sOutput.format), &p_sFormat, sizeof(media_format)); strncpy(p_vpName, m_sOutput.name, B_MEDIA_NAME_LENGTH); // Now that we're connected, we can determine our downstream latency. // Do so, then make sure we get our events early enough. media_node_id id; FindLatencyFor(m_sOutput.destination, &mLatency, &id); mInternalLatency = 2000; SetEventLatency(mLatency + mInternalLatency); // reset our buffer duration, etc. to avoid later calculations bigtime_t duration = GetBufferDuration(); SetBufferDuration(duration); }