// how should we handle late buffers? drop them? // notify the producer? status_t ESDSinkNode::HandleBuffer( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent) { CALLED(); BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); if (buffer == 0) { fprintf(stderr,"<- B_BAD_VALUE\n"); return B_BAD_VALUE; } if(fInput.destination.id != buffer->Header()->destination) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); return B_MEDIA_BAD_DESTINATION; } media_header* hdr = buffer->Header(); bigtime_t now = TimeSource()->Now(); bigtime_t perf_time = hdr->start_time; // the how_early calculate here doesn't include scheduling latency because // we've already been scheduled to handle the buffer bigtime_t how_early = perf_time - EventLatency() - now; // if the buffer is late, we ignore it and report the fact to the producer // who sent it to us if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode... (RunMode() != B_RECORDING) && // ...or in recording mode (how_early < 0LL)) { //mLateBuffers++; NotifyLateProducer(fInput.source, -how_early, perf_time); fprintf(stderr," <- LATE BUFFER : %lli\n", how_early); buffer->Recycle(); } else { if (fDevice->CanSend()) fDevice->Write(buffer->Data(), buffer->SizeUsed()); } return B_OK; }
BBuffer* AudioProducer::_FillNextBuffer(bigtime_t eventTime) { BBuffer* buffer = fBufferGroup->RequestBuffer( fOutput.format.u.raw_audio.buffer_size, BufferDuration()); if (!buffer) { ERROR("AudioProducer::_FillNextBuffer() - no buffer\n"); return NULL; } size_t sampleSize = fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; size_t numSamples = fOutput.format.u.raw_audio.buffer_size / sampleSize; // number of sample in the buffer // fill in the buffer header media_header* header = buffer->Header(); header->type = B_MEDIA_RAW_AUDIO; header->time_source = TimeSource()->ID(); buffer->SetSizeUsed(fOutput.format.u.raw_audio.buffer_size); bigtime_t performanceTime = bigtime_t(double(fFramesSent) * 1000000.0 / double(fOutput.format.u.raw_audio.frame_rate)); // fill in data from audio supplier int64 frameCount = numSamples / fOutput.format.u.raw_audio.channel_count; bigtime_t startTime = performanceTime; bigtime_t endTime = bigtime_t(double(fFramesSent + frameCount) * 1000000.0 / fOutput.format.u.raw_audio.frame_rate); if (!fSupplier || fSupplier->InitCheck() != B_OK || fSupplier->GetFrames(buffer->Data(), frameCount, startTime, endTime) != B_OK) { ERROR("AudioProducer::_FillNextBuffer() - supplier error -> silence\n"); memset(buffer->Data(), 0, buffer->SizeUsed()); } // stamp buffer if (RunMode() == B_RECORDING) { header->start_time = eventTime; } else { header->start_time = fStartTime + performanceTime; } #if DEBUG_TO_FILE BMediaTrack* track; if (BMediaFile* file = init_media_file(fOutput.format, &track)) { track->WriteFrames(buffer->Data(), frameCount); } #endif // DEBUG_TO_FILE if (fPeakListener && fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT) { // TODO: extend the peak notifier for other sample formats int32 channels = fOutput.format.u.raw_audio.channel_count; float max[channels]; float min[channels]; for (int32 i = 0; i < channels; i++) { max[i] = -1.0; min[i] = 1.0; } float* sample = (float*)buffer->Data(); for (uint32 i = 0; i < frameCount; i++) { for (int32 k = 0; k < channels; k++) { if (*sample < min[k]) min[k] = *sample; if (*sample > max[k]) max[k] = *sample; sample++; } } BMessage message(MSG_PEAK_NOTIFICATION); for (int32 i = 0; i < channels; i++) { float maxAbs = max_c(fabs(min[i]), fabs(max[i])); message.AddFloat("max", maxAbs); } bigtime_t realTime = TimeSource()->RealTimeFor( fStartTime + performanceTime, 0); MessageEvent* event = new (std::nothrow) MessageEvent(realTime, fPeakListener, message); if (event != NULL) EventQueue::Default().AddEvent(event); } return buffer; }
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? }
int main() { // app_server connection (no need to run it) BApplication app("application/x-vnd-test"); BBufferGroup * group; status_t s; int32 count; BBuffer *buffer; /* printf("using default constructor:\n"); group = new BBufferGroup(); s = group->InitCheck(); printf("InitCheck: status = %ld\n",s); s = group->CountBuffers(&count); printf("CountBuffers: count = %ld, status = %ld\n",count,s); delete group; */ printf("\n"); printf("using size = 1234 constructor:\n"); group = new BBufferGroup(1234); s = group->InitCheck(); printf("InitCheck: status = %ld\n",s); s = group->CountBuffers(&count); printf("CountBuffers: count = %ld, status = %ld\n",count,s); s = group->GetBufferList(1,&buffer); printf("GetBufferList: status = %ld\n",s); printf("Buffer->Data: = %08x\n",(int)buffer->Data()); printf("Buffer->ID: = %d\n",(int)buffer->ID()); printf("Buffer->Size: = %ld\n",buffer->Size()); printf("Buffer->SizeAvailable: = %ld\n",buffer->SizeAvailable()); printf("Buffer->SizeUsed: = %ld\n",buffer->SizeUsed()); printf("\n"); media_buffer_id id = buffer->ID(); BBufferGroup * group2 = new BBufferGroup(1,&id); printf("creating second group with a buffer from first group:\n"); s = group2->InitCheck(); printf("InitCheck: status = %ld\n",s); s = group2->CountBuffers(&count); printf("CountBuffers: count = %ld, status = %ld\n",count,s); buffer = 0; s = group2->GetBufferList(1,&buffer); printf("GetBufferList: status = %ld\n",s); printf("Buffer->Data: = %08x\n",(int)buffer->Data()); printf("Buffer->ID: = %d\n",(int)buffer->ID()); printf("Buffer->Size: = %ld\n",buffer->Size()); printf("Buffer->SizeAvailable: = %ld\n",buffer->SizeAvailable()); printf("Buffer->SizeUsed: = %ld\n",buffer->SizeUsed()); delete group; delete group2; printf("\n"); /* printf("creating a BSmallBuffer:\n"); BSmallBuffer * sb = new BSmallBuffer; printf("sb->Data: = %08x\n",(int)sb->Data()); printf("sb->ID: = %d\n",(int)sb->ID()); printf("sb->Size: = %ld\n",sb->Size()); printf("sb->SizeAvailable: = %ld\n",sb->SizeAvailable()); printf("sb->SizeUsed: = %ld\n",sb->SizeUsed()); printf("sb->SmallBufferSizeLimit: = %ld\n",sb->SmallBufferSizeLimit()); delete sb; */ return 0; }