Beispiel #1
0
void
ProducerNode::BufferProducer()
{
	// this thread produces one buffer each two seconds,
	// and shedules it to be handled one second later than produced
	// assuming a realtime timesource

	status_t rv;
	for (;;) {
		rv = acquire_sem_etc(mBufferProducerSem,1,B_RELATIVE_TIMEOUT,DELAY);
		if (rv == B_INTERRUPTED) {
			continue;
		} else if (rv == B_OK) {
			// triggered by AdditionalBufferRequested
			release_sem(mBufferProducerSem);
		} else if (rv != B_TIMED_OUT) {
			// triggered by deleting the semaphore (stop request)
			break;
		}
		if (!mOutputEnabled)
			continue;
			
		BBuffer *buffer;
//		out("ProducerNode: RequestBuffer\n");
		buffer = mBufferGroup->RequestBuffer(2048);
		if (!buffer) {
		}
		buffer->Header()->start_time = TimeSource()->Now() + DELAY / 2;
		out("ProducerNode: SendBuffer, sheduled time = %5.4f\n",buffer->Header()->start_time / 1E6);
		rv = SendBuffer(buffer, mOutput.destination);
		if (rv != B_OK) {
		}
	}
}
Beispiel #2
0
bigtime_t
EqualizerNode::GetFilterLatency(void)
{
    if (fOutputMedia.destination == media_destination::null)
        return 0LL;

    BBufferGroup* test_group =
        new BBufferGroup(fOutputMedia.format.u.raw_audio.buffer_size, 1);

    BBuffer* buffer =
        test_group->RequestBuffer(fOutputMedia.format.u.raw_audio.buffer_size);
    buffer->Header()->type = B_MEDIA_RAW_AUDIO;
    buffer->Header()->size_used = fOutputMedia.format.u.raw_audio.buffer_size;

    bigtime_t begin = system_time();
    FilterBuffer(buffer);
    bigtime_t latency = system_time() - begin;

    buffer->Recycle();
    delete test_group;

    InitFilter();

    return latency;
}
// figure processing latency by doing 'dry runs' of filterBuffer()
bigtime_t StepMotionBlurFilter::calcProcessingLatency() {
	PRINT(("StepMotionBlurFilter::calcProcessingLatency()\n"));
	
	if(m_output.destination == media_destination::null) {
		PRINT(("\tNot connected.\n"));
		return 0LL;
	}
	
	// allocate a temporary buffer group
	BBufferGroup* pTestGroup = new BBufferGroup(m_output.format.u.raw_video.display.line_width * m_output.format.u.raw_video.display.line_count *4, 1);
	
	// fetch a buffer
	BBuffer* pBuffer = pTestGroup->RequestBuffer(m_output.format.u.raw_video.display.line_width * m_output.format.u.raw_video.display.line_count * 4);
	ASSERT(pBuffer);
	
	pBuffer->Header()->type = B_MEDIA_RAW_VIDEO;
	pBuffer->Header()->size_used = m_output.format.u.raw_video.display.line_width * m_output.format.u.raw_video.display.line_count * 4;
	
	// run the test
	bigtime_t preTest = system_time();
	filterBuffer(pBuffer);
	bigtime_t elapsed = system_time()-preTest;
	
	// clean up
	pBuffer->Recycle();
	delete pTestGroup;

	// reset filter state
	initFilter();

	return elapsed;
}
Beispiel #4
0
// -------------------------------------------------------- //
// implementation for BMediaEventLooper
// -------------------------------------------------------- //
// protected:
status_t MediaReader::HandleBuffer(
				const media_timed_event *event,
				bigtime_t lateness,
				bool realTimeEvent)
{
	CALLED();

	if (output.destination == media_destination::null)
		return B_MEDIA_NOT_CONNECTED;

	status_t status = B_OK;
	BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
	if (buffer != 0) {
	    status = FillFileBuffer(buffer);
	    if (status != B_OK) {
			PRINT("MediaReader::HandleEvent got an error from FillFileBuffer.\n");
			buffer->Recycle();
		} else {
			if (fOutputEnabled) {
				status = SendBuffer(buffer,output.destination);
				if (status != B_OK) {
					PRINT("MediaReader::HandleEvent got an error from SendBuffer.\n");
					buffer->Recycle();
				}
			} else {
				buffer->Recycle();
			}
		}
	}
	bigtime_t nextEventTime = event->event_time+fBufferPeriod;
	media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER);
	EventQueue()->AddEvent(nextBufferEvent);
	return status;
}
Beispiel #5
0
void
ClientNode::_DataAvailable(bigtime_t time)
{
    size_t samples = fFormat.u.raw_audio.buffer_size / sizeof(float);
    fFramesSent += samples;

    JackPortList* ports = fOwner->GetOutputPorts();
    for (int i = 0; i < ports->CountItems(); i++) {
        JackPort* port = ports->ItemAt(i);
        if (port != NULL && port->IsConnected()) {

            BBuffer* buffer = FillNextBuffer(time, port);

            if (buffer) {
                if (SendBuffer(buffer,
                               port->MediaOutput()->source, port->MediaOutput()->destination)
                        != B_OK) {

                    printf("ClientNode::_DataAvailable: Buffer sending "
                           "failed\n");
                    buffer->Recycle();
                }
                size_t nFrames = fFormat.u.raw_audio.buffer_size
                                 / ((fFormat.u.raw_audio.format
                                     & media_raw_audio_format::B_AUDIO_SIZE_MASK)
                                    * fFormat.u.raw_audio.channel_count);
            }

            if (buffer == NULL)
                return;
        }
    }
}
Beispiel #6
0
BBuffer*
SoundPlayNode::FillNextBuffer(bigtime_t eventTime)
{
	CALLED();

	// get a buffer from our buffer group
	BBuffer* buffer = fBufferGroup->RequestBuffer(
		fOutput.format.u.raw_audio.buffer_size, BufferDuration() / 2);

	// If we fail to get a buffer (for example, if the request times out), we
	// skip this buffer and go on to the next, to avoid locking up the control
	// thread
	if (buffer == NULL) {
		ERROR("SoundPlayNode::FillNextBuffer: RequestBuffer failed\n");
		return NULL;
	}

	if (fPlayer->HasData()) {
		fPlayer->PlayBuffer(buffer->Data(),
			fOutput.format.u.raw_audio.buffer_size, fOutput.format.u.raw_audio);
	} else
		memset(buffer->Data(), 0, fOutput.format.u.raw_audio.buffer_size);

	// fill in the buffer header
	media_header* header = buffer->Header();
	header->type = B_MEDIA_RAW_AUDIO;
	header->size_used = fOutput.format.u.raw_audio.buffer_size;
	header->time_source = TimeSource()->ID();
	header->start_time = eventTime;

	return buffer;
}
Beispiel #7
0
// figure processing latency by doing 'dry runs' of filterBuffer()
bigtime_t FlangerNode::calcProcessingLatency() {
	PRINT(("FlangerNode::calcProcessingLatency()\n"));

	if(m_output.destination == media_destination::null) {
		PRINT(("\tNot connected.\n"));
		return 0LL;
	}

	// allocate a temporary buffer group
	BBufferGroup* pTestGroup = new BBufferGroup(
		m_output.format.u.raw_audio.buffer_size, 1);

	// fetch a buffer
	BBuffer* pBuffer = pTestGroup->RequestBuffer(
		m_output.format.u.raw_audio.buffer_size);
	ASSERT(pBuffer);

	pBuffer->Header()->type = B_MEDIA_RAW_AUDIO;
	pBuffer->Header()->size_used = m_output.format.u.raw_audio.buffer_size;

	// run the test
	bigtime_t preTest = system_time();
	filterBuffer(pBuffer);
	bigtime_t elapsed = system_time()-preTest;

	// clean up
	pBuffer->Recycle();
	delete pTestGroup;

	// reset filter state
	initFilter();

	return elapsed;
}
Beispiel #8
0
  BINLINE void BMessageHeader::read(BBuffer& bbuf) {
    bbuf.setByteOrder(BBIG_ENDIAN);
    bool cmpr = bbuf.setCompressInteger(false);

    bbuf.serialize(magic);

    switch(magic) {
    case BMAGIC_BINARY_STREAM:
      break;
    case BMAGIC_BINARY_STREAM_LE:
      magic = BMAGIC_BINARY_STREAM;
      bbuf.setByteOrder(BLITTLE_ENDIAN);
      break;
    default:
      throw BException(BExceptionC::CORRUPT, L"Stream must start with BYPS or SPYB");
    }

    bbuf.serialize(error);
    bbuf.serialize(flags);

    if (flags & BHEADER_FLAG_BYPS_VERSION) {
      bbuf.serialize(bversion);
    }

    bbuf.serialize(version);
    targetId.serialize(bbuf, bversion);
    bbuf.serialize(messageId);

    bbuf.setCompressInteger(cmpr);

    if (bversion >= BHEADER_BYPS_VERSION_WITH_SESSIONID) {
      sessionId = BTargetId::readSessionId(bbuf);
    }
  }
Beispiel #9
0
void
FireWireDVNode::card_reader_thread()
{
	status_t err;
	size_t rbufsize;
	int rcount;

	fCard->GetBufInfo(&rbufsize, &rcount);
	delete fBufferGroupEncVideo;
	fBufferGroupEncVideo = new BBufferGroup(rbufsize, rcount);
	while (!fTerminateThreads) {
		void *data, *end;
		ssize_t sizeUsed = fCard->Read(&data);
		if (sizeUsed < 0) {
			TRACE("FireWireDVNode::%s: %s\n", __FUNCTION__,
				strerror(sizeUsed));
			continue;
		}

		end = (char*)data + sizeUsed;

		while (data < end) {
			BBuffer* buf = fBufferGroupEncVideo->RequestBuffer(rbufsize, 10000);
			if (!buf) {
				TRACE("OutVideo: request buffer timout\n");
				continue;
			}
			
			err = fCard->Extract(buf->Data(), &data, &sizeUsed);
			if (err) {
				buf->Recycle();
				printf("OutVideo Extract error %s\n", strerror(err));
				continue;
			}
	
			media_header* hdr = buf->Header();
			hdr->type = B_MEDIA_ENCODED_VIDEO;
			hdr->size_used = sizeUsed;
			hdr->time_source = TimeSource()->ID();	// set time source id
			//what should the start_time be?
			hdr->start_time = TimeSource()->PerformanceTimeFor(system_time());

			fLock.Lock();
			if (SendBuffer(buf, fOutputEncVideo.source,
					fOutputEncVideo.destination) != B_OK) {
				TRACE("OutVideo: sending buffer failed\n");
				buf->Recycle();
			} 
			fLock.Unlock();
		}
		
	}
}
Beispiel #10
0
BBuffer*
GameProducer::FillNextBuffer(bigtime_t event_time)
{
	// get a buffer from our buffer group
	BBuffer* buf = fBufferGroup->RequestBuffer(fBufferSize, BufferDuration());

	// if we fail to get a buffer (for example, if the request times out), we
	// skip this buffer and go on to the next, to avoid locking up the control
	// thread.
	if (!buf)
		return NULL;

	// we need to discribe the buffer
	int64 frames = int64(fBufferSize / fFrameSize);
	memset(buf->Data(), 0, fBufferSize);

	// now fill the buffer with data, continuing where the last buffer left off
	fObject->Play(buf->Data(), frames);

	// fill in the buffer header
	media_header* hdr = buf->Header();
	hdr->type = B_MEDIA_RAW_AUDIO;
	hdr->size_used = fBufferSize;
	hdr->time_source = TimeSource()->ID();

	bigtime_t stamp;
	if (RunMode() == B_RECORDING) {
		// In B_RECORDING mode, we stamp with the capture time.  We're not
		// really a hardware capture node, but we simulate it by using the
		// (precalculated) time at which this buffer "should" have been created.
		stamp = event_time;
	} else {
		// okay, we're in one of the "live" performance run modes.  in these
		// modes, we stamp the buffer with the time at which the buffer should
		// be rendered to the output, not with the capture time. fStartTime is
		// the cached value of the first buffer's performance time; we calculate
		// this buffer's performance time as an offset from that time, based on
		// the amount of media we've created so far.
		// Recalculating every buffer like this avoids accumulation of error.
		stamp = fStartTime + bigtime_t(double(fFramesSent)
			/ double(fOutput.format.u.raw_audio.frame_rate) * 1000000.0);
	}
	hdr->start_time = stamp;

	return buf;
}
Beispiel #11
0
// figure processing latency by doing 'dry runs' of processBuffer()
bigtime_t AudioFilterNode::calcProcessingLatency() {

	PRINT(("AudioFilterNode::calcProcessingLatency()\n"));
	
	ASSERT(m_input.source != media_source::null);
	ASSERT(m_output.destination != media_destination::null);
	ASSERT(m_op);

	// initialize filter
	m_op->init();

	size_t maxSize = max_c(
		m_input.format.u.raw_audio.buffer_size,
		m_output.format.u.raw_audio.buffer_size);

	// allocate a temporary buffer group
	BBufferGroup* testGroup = new BBufferGroup(
		maxSize, 1);
	
	// fetch a buffer big enough for in-place processing
	BBuffer* buffer = testGroup->RequestBuffer(
		maxSize, -1);
	ASSERT(buffer);
	
	buffer->Header()->type = B_MEDIA_RAW_AUDIO;
	buffer->Header()->size_used = m_input.format.u.raw_audio.buffer_size;
	
	// run the test
	bigtime_t preTest = system_time();
	processBuffer(buffer, buffer);
	bigtime_t elapsed = system_time()-preTest;
	
	// clean up
	buffer->Recycle();
	delete testGroup;

	// reset filter state
	m_op->init();

	return elapsed;// + 100000LL;
}
Beispiel #12
0
void
AudioConsumer::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");
			if (RunState() == B_STARTED) {
				// log latency

				BBuffer* buffer = (BBuffer*)event->pointer;
				buffer->Recycle();
			}
			break;
		}

		default:
			break;
	}
}
Beispiel #13
0
BBuffer*
ClientNode::FillNextBuffer(bigtime_t eventTime, JackPort* port)
{
    //printf("FillNextBuffer\n");

    BBuffer* buffer = port->CurrentBuffer();

    media_header* header = buffer->Header();
    header->type = B_MEDIA_RAW_AUDIO;
    header->size_used = fFormat.u.raw_audio.buffer_size;
    header->time_source = TimeSource()->ID();

    bigtime_t start;
    if (RunMode() == B_RECORDING)
        start = eventTime;
    else
        start = fTime + bigtime_t(double(fFramesSent)
                                  / double(fFormat.u.raw_audio.frame_rate) * 1000000.0);

    header->start_time = start;

    return buffer;
}
Beispiel #14
0
status_t
ClientNode::_InitOutputPorts()
{
    //printf("JackClient::_InitOutputPorts()\n");
    JackPortList* outputPorts = fOwner->GetOutputPorts();

    for (int i = 0; i < outputPorts->CountItems(); i++) {
        JackPort* port = outputPorts->ItemAt(i);
        if (!port->IsConnected())
            return B_ERROR;

        BBuffer* buffer = fBufferGroup->RequestBuffer(
                              fFormat.u.raw_audio.buffer_size);

        if (buffer == NULL || buffer->Data() == NULL) {
            printf("RequestBuffer failed\n");
            return B_ERROR;
        }

        port->SetProcessingBuffer(buffer);
    }
    return B_OK;
}
Beispiel #15
0
  BINLINE void BMessageHeader::write(BBuffer& bbuf) {
    bool cmpr = bbuf.setCompressInteger(false);
    bbuf.setByteOrder(byteOrder);
    bbuf.serialize(magic);
    bbuf.serialize(error);
    bbuf.serialize(flags);

    if (flags & BHEADER_FLAG_BYPS_VERSION) {
      bbuf.serialize(bversion);
    }

    bbuf.serialize(version);
    targetId.serialize(bbuf, bversion);
    bbuf.serialize(messageId);
    bbuf.setCompressInteger(cmpr);

    if (bversion >= BHEADER_BYPS_VERSION_WITH_SESSIONID) {
      BTargetId::writeSessionId(bbuf, sessionId);
    }
  }
Beispiel #16
0
// 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;
}
Beispiel #17
0
// _FrameGenerator
int32 
VideoProducer::_FrameGenerator()
{
	bool forceSendingBuffer = true;
	bigtime_t lastFrameSentAt = 0;
	bool running = true;
	while (running) {
ldebug("VideoProducer: loop: %Ld\n", fFrame);
		// lock the node manager
		status_t err = fManager->LockWithTimeout(10000);
		bool ignoreEvent = false;
		// Data to be retrieved from the node manager.
		bigtime_t performanceTime = 0;
		bigtime_t nextPerformanceTime = 0;
		bigtime_t waitUntil = 0;
		bigtime_t nextWaitUntil = 0;
		bigtime_t maxRenderTime = 0;
		int32 playingDirection = 0;
		int64 playlistFrame = 0;
		switch (err) {
			case B_OK: {
ldebug("VideoProducer: node manager successfully locked\n");
				// get the times for the current and the next frame
				performanceTime = fManager->TimeForFrame(fFrame);
				nextPerformanceTime = fManager->TimeForFrame(fFrame + 1);
				maxRenderTime = min_c(bigtime_t(33334 * 0.9),
									  max_c(fSupplier->ProcessingLatency(), maxRenderTime));

				waitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase
													+ performanceTime, 0) - maxRenderTime;
				nextWaitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase
													+ nextPerformanceTime, 0) - maxRenderTime;
				// get playing direction and playlist frame for the current frame
				bool newPlayingState;
				playlistFrame = fManager->PlaylistFrameAtFrame(fFrame,
															   playingDirection,
															   newPlayingState);
ldebug("VideoProducer: performance time: %Ld, playlist frame: %Ld\n",
performanceTime, playlistFrame);
				forceSendingBuffer |= newPlayingState;
				fManager->SetCurrentVideoTime(nextPerformanceTime);
				fManager->Unlock();
				break;
			}
			case B_TIMED_OUT:
ldebug("VideoProducer: Couldn't lock the node manager.\n");
				ignoreEvent = true;
				waitUntil = system_time() - 1;
				break;
			default:
				printf("Couldn't lock the node manager. Terminating video producer "
					   "frame generator thread.\n");
				ignoreEvent = true;
				waitUntil = system_time() - 1;
				running = false;
				break;
		}
		// Force sending a frame, if the last one has been sent more than
		// one second ago.
		if (lastFrameSentAt + 1000000 < performanceTime)
			forceSendingBuffer = true;

ldebug("VideoProducer: waiting (%Ld)...\n", waitUntil);
		// wait until...
		err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, waitUntil);
		// The only acceptable responses are B_OK and B_TIMED_OUT. Everything
		// else means the thread should quit. Deleting the semaphore, as in
		// VideoProducer::_HandleStop(), will trigger this behavior.
		switch (err) {
			case B_OK:
ldebug("VideoProducer::_FrameGenerator - going back to sleep.\n");
				break;
			case B_TIMED_OUT:
ldebug("VideoProducer: timed out => event\n");
				// Catch the cases in which the node manager could not be
				// locked and we therefore have no valid data to work with,
				// or the producer is not running or enabled.
				if (ignoreEvent || !fRunning || !fEnabled) {
ldebug("VideoProducer: ignore event\n");
					// nothing to do
				// Drop frame if it's at least a frame late.
				} else if (nextWaitUntil < system_time()) {
//printf("VideoProducer: dropped frame (%ld)\n", fFrame);
					if (fManager->LockWithTimeout(10000) == B_OK) {
						fManager->FrameDropped();
						fManager->Unlock();
					}
					// next frame
					fFrame++;
				// Send buffers only, if playing, the node is running and the
				// output has been enabled
				} else if (playingDirection != 0 || forceSendingBuffer) {
ldebug("VideoProducer: produce frame\n");
					BAutolock _(fLock);
					// Fetch a buffer from the buffer group
					BBuffer *buffer = fUsedBufferGroup->RequestBuffer(
						fConnectedFormat.display.bytes_per_row
						* fConnectedFormat.display.line_count, 0LL);
					if (buffer) {
						// Fill out the details about this buffer.
						media_header *h = buffer->Header();
						h->type = B_MEDIA_RAW_VIDEO;
						h->time_source = TimeSource()->ID();
						h->size_used = fConnectedFormat.display.bytes_per_row
									   * fConnectedFormat.display.line_count;
						// For a buffer originating from a device, you might
						// want to calculate this based on the
						// PerformanceTimeFor the time your buffer arrived at
						// the hardware (plus any applicable adjustments).
						h->start_time = fPerformanceTimeBase + performanceTime;
						h->file_pos = 0;
						h->orig_size = 0;
						h->data_offset = 0;
						h->u.raw_video.field_gamma = 1.0;
						h->u.raw_video.field_sequence = fFrame;
						h->u.raw_video.field_number = 0;
						h->u.raw_video.pulldown_number = 0;
						h->u.raw_video.first_active_line = 1;
						h->u.raw_video.line_count
							= fConnectedFormat.display.line_count;
						// Fill in a frame
						media_format mf;
						mf.type = B_MEDIA_RAW_VIDEO;
						mf.u.raw_video = fConnectedFormat;
ldebug("VideoProducer: frame: %Ld, playlistFrame: %Ld\n", fFrame, playlistFrame);
						bool forceOrWasCached = forceSendingBuffer;
	
//						if (fManager->LockWithTimeout(5000) == B_OK) {
							// we need to lock the manager, or our
							// fSupplier might work on bad data
							err = fSupplier->FillBuffer(playlistFrame,
														buffer->Data(), &mf,
														forceOrWasCached);
//							fManager->Unlock();
//						} else {
//							err = B_ERROR;
//						}
						// clean the buffer if something went wrong
						if (err != B_OK) {
							memset(buffer->Data(), 0, h->size_used);
							err = B_OK;
						}
						// Send the buffer on down to the consumer
						if (!forceOrWasCached) {
							if (SendBuffer(buffer, fOutput.source,
									fOutput.destination) != B_OK) {
								printf("_FrameGenerator: Error sending buffer\n");
								// If there is a problem sending the buffer,
								// or if we don't send the buffer because its
								// contents are the same as the last one,
								// return it to its buffer group.
								buffer->Recycle();
								// we tell the supplier to delete
								// its caches if there was a problem sending
								// the buffer
								fSupplier->DeleteCaches();
							}
						} else
							buffer->Recycle();
						// Only if everything went fine we clear the flag
						// that forces us to send a buffer even if not
						// playing.
						if (err == B_OK) {
							forceSendingBuffer = false;
							lastFrameSentAt = performanceTime;
						}
					}
else ldebug("no buffer!\n");
					// next frame
					fFrame++;
				} else {
ldebug("VideoProducer: not playing\n");
					// next frame
					fFrame++;
				}
				break;
			default:
ldebug("Couldn't acquire semaphore. Error: %s\n", strerror(err));
				running = false;
				break;
		}
	}
ldebug("VideoProducer: frame generator thread done.\n");
	return B_OK;
}
Beispiel #18
0
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;
}
Beispiel #19
0
void
TVideoPreviewView::DisplayThread()
{
	FUNCTION("TVideoPreviewView::DisplayThread\n");

	bigtime_t timeout = 5000;
	bigtime_t realTimeNow = 0;
	bigtime_t perfTimeNow = 0;
	bigtime_t halfPeriod = (bigtime_t) (500000./29.97);
	bool timeSourceRunning = false;

	while (!mDisplayQuit) {
		if (acquire_sem(mServiceLock) == B_NO_ERROR) {
			timeSourceRunning = TimeSource()->IsRunning();
			realTimeNow = BTimeSource::RealTime();
			perfTimeNow = TimeSource()->Now();
			release_sem(mServiceLock);
		}

		snooze(timeout);

		if (timeSourceRunning) {

			// if we received a Stop, deal with it
			if (mStopping) {
				PROGRESS("VidConsumer::DisplayThread - STOP\n");
				if (perfTimeNow >= mStopTime) {
					mRunning = false;
					mStopping = false;

					// deal with any pending Seek
					if (mSeeking)
						mSeeking = false;

					//if (mConnected)
					//	SendDataStatus(B_DATA_NOT_AVAILABLE, mConnections[0], mStopTime);

					continue;
				}
			}

			// if we received a Seek, deal with it
			if (mSeeking) {
				PROGRESS("VidConsumer::DisplayThread - SEEK\n");
				if (perfTimeNow >= mSeekTime) {
					PROGRESS("VidConsumer::DisplayThread - DO SEEK\n");
					mSeeking = false;
					mDeltaTime = mMediaTime;

					continue;
				}
			}

			// if we received a Start, deal with it
			if (mStarting) {
				PROGRESS("BBt848Controllable::CaptureRun mStartTime = %.4f TimeNow = %.4f\n", (double)mStartTime/M1, (double)perfTimeNow/M1);
				if (perfTimeNow >= mStartTime) {
					mRunning = true;
					mStarting = false;
					mDeltaTime = mStartTime;

					//if (mConnected)
					//	SendDataStatus(B_DATA_AVAILABLE, mConnections[0], mStartTime);

					continue;
				}
			}

			if (mRunning) {
				// check for buffer available.
				status_t err = acquire_sem_etc(mBufferAvailable, 1, B_TIMEOUT, halfPeriod * 2);

				if (err == B_TIMED_OUT || !mConnected) {
					ERROR("VidConsumer::DisplayThread - Error from acquire_sem_etc: 0x%lx\n", err);
					continue;
				}

				BBuffer* buffer = mBufferQueue->PopFirstBuffer(0);

				LOOP("Popped buffer %08x, Start time: %.4f, system time: %.4f diff: %.4f\n",
				     buffer,
				     (double) buffer->Header()->start_time/M1,
				     (double) perfTimeNow/M1,
				     (double) (buffer->Header()->start_time - perfTimeNow)/M1);

				// Display frame if we're in B_OFFLINE mode or
				// within +/- a half frame time of start time
				if ( (mRunMode == B_OFFLINE) ||
				     ((perfTimeNow > (buffer->Header()->start_time - halfPeriod)) &&
				      (perfTimeNow < (buffer->Header()->start_time + halfPeriod))) ) {
					uint32 bpp = (mColorspace == B_RGB32 ? 4 : 2);
					memcpy(m_Bitmap->Bits(), buffer->Data(), mRowBytes * mYSize * bpp);
					buffer->Header()->start_time = system_time();
					buffer->Recycle();
					bigtime_t t1 = system_time();

					//	Update view
					if (LockLooper()) {
						DrawBitmap(m_Bitmap, Bounds());
						UnlockLooper();
					}

					t1 = system_time() - t1;
					if (t1/M1 > .030)
						printf("Draw time = %.4f\n",t1/M1);
					continue;
				} else {
					// If we're too early, push frame back on stack
					if (perfTimeNow < buffer->Header()->start_time) {
						LOOP("push buffer back on stack!\n");
						mBufferQueue->PushBuffer(buffer, buffer->Header()->start_time);
						release_sem(mBufferAvailable);
						continue;
					} else {
						// if we've already passed a half frame time past the buffer start time
						// and RunMode = INCREASE_LATENCY, increase latency and display the frame
						if ( (perfTimeNow > buffer->Header()->start_time) &&
						     (mRunMode == B_INCREASE_LATENCY)) {
							mMyLatency += halfPeriod;
							ERROR("VidConsumer::DisplayThread - Increased latency to: %.4f\n", mMyLatency);
							ERROR("	 Performance time: %.4f @ %.4f\n", (double)buffer->Header()->start_time/M1, (double)perfTimeNow/M1);
							uint32 bpp = (mColorspace == B_RGB32 ? 4 : 2);
							memcpy(m_Bitmap->Bits(), buffer->Data(), mRowBytes * mYSize * bpp);
							buffer->Recycle();

							// should send late notice
							if (LockLooper()) {
								DrawBitmap(m_Bitmap, Bounds());
								UnlockLooper();
							}

							continue;
						} else {
							// we're more than a half frame time past the buffer start time
							// drop the frame
							ERROR("VidConsumer::DisplayThread - dropped late frame: %.4f @ %.4f\n", (double)buffer->Header()->start_time/M1, (double)perfTimeNow/M1);
							buffer->Recycle();
							// should send late notice
							continue;
						}
					}
				}
			}
			snooze(timeout);
		}  else snooze(timeout); // if TimeSource stopped
	} // while (!mTimeToQuit)
}
Beispiel #20
0
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;
}
Beispiel #21
0
void
AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
	bool realTimeEvent)
{
	TRACE_BUFFER("%p->AudioProducer::HandleEvent()\n", this);

	switch (event->type) {
		case BTimedEventQueue::B_START:
			TRACE("AudioProducer::HandleEvent(B_START)\n");
			if (RunState() != B_STARTED) {
				fFramesSent = 0;
				fStartTime = event->event_time + fSupplier->InitialLatency();
printf("B_START: start time: %lld\n", fStartTime);
				media_timed_event firstBufferEvent(
					fStartTime - fSupplier->InitialLatency(),
					BTimedEventQueue::B_HANDLE_BUFFER);
				EventQueue()->AddEvent(firstBufferEvent);
			}
			TRACE("AudioProducer::HandleEvent(B_START) done\n");
			break;

		case BTimedEventQueue::B_STOP:
			TRACE("AudioProducer::HandleEvent(B_STOP)\n");
			EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
				BTimedEventQueue::B_HANDLE_BUFFER);
			TRACE("AudioProducer::HandleEvent(B_STOP) done\n");
			break;

		case BTimedEventQueue::B_HANDLE_BUFFER:
		{
			TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n");
			if (RunState() == BMediaEventLooper::B_STARTED
				&& fOutput.destination != media_destination::null) {
				BBuffer* buffer = _FillNextBuffer(event->event_time);
				if (buffer) {
					status_t err = B_ERROR;
					if (fOutputEnabled) {
						err = SendBuffer(buffer, fOutput.source,
							fOutput.destination);
					}
					if (err)
						buffer->Recycle();
				}
				size_t sampleSize = fOutput.format.u.raw_audio.format
						& media_raw_audio_format::B_AUDIO_SIZE_MASK;

				size_t nFrames = fOutput.format.u.raw_audio.buffer_size
					/ (sampleSize * fOutput.format.u.raw_audio.channel_count);
				fFramesSent += nFrames;

				fNextScheduledBuffer = fStartTime
					+ bigtime_t(double(fFramesSent) * 1000000.0
						/ double(fOutput.format.u.raw_audio.frame_rate));
				media_timed_event nextBufferEvent(fNextScheduledBuffer,
					BTimedEventQueue::B_HANDLE_BUFFER);
				EventQueue()->AddEvent(nextBufferEvent);
			} else {
				ERROR("B_HANDLE_BUFFER, but not started!\n");
			}
			TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
			break;
		}
		default:
			break;
	}
}
Beispiel #22
0
void
GameProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
	bool realTimeEvent)
{
//	FPRINTF(stderr, "ToneProducer::HandleEvent\n");
	switch (event->type)
	{
	case BTimedEventQueue::B_START:
		// don't do anything if we're already running
		if (RunState() != B_STARTED) {
			// Going to start sending buffers so setup the needed bookkeeping
			fFramesSent = 0;
			fStartTime = event->event_time;
			media_timed_event firstBufferEvent(fStartTime,
				BTimedEventQueue::B_HANDLE_BUFFER);

			// Alternatively, we could call HandleEvent() directly with this
			// event, to avoid a trip through the event queue like this:
			//		this->HandleEvent(&firstBufferEvent, 0, false);
			EventQueue()->AddEvent(firstBufferEvent);
		}
		break;

	case BTimedEventQueue::B_STOP:
		// When we handle a stop, we must ensure that downstream consumers don't
		// get any more buffers from us.  This means we have to flush any
		// pending buffer-producing events from the queue.
		EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
			BTimedEventQueue::B_HANDLE_BUFFER);
		break;

	case BTimedEventQueue::B_HANDLE_BUFFER:
		{
			// Ensure we're both started and connected before delivering buffer
			if ((RunState() == BMediaEventLooper::B_STARTED)
				&& (fOutput.destination != media_destination::null)) {
				// Get the next buffer of data
				BBuffer* buffer = FillNextBuffer(event->event_time);
				if (buffer) {
					// Send the buffer downstream if output is enabled
					status_t err = B_ERROR;
					if (fOutputEnabled) {
						err = SendBuffer(buffer, fOutput.source,
							fOutput.destination);
					}
					if (err) {
						// we need to recycle the buffer ourselves if output is
						// disabled or if the call to SendBuffer() fails
						buffer->Recycle();
					}
				}

				// track how much media we've delivered so far
				size_t nFrames = fBufferSize / fFrameSize;
				fFramesSent += nFrames;

				// The buffer is on its way; now schedule the next one to go
				bigtime_t nextEvent = fStartTime + bigtime_t(double(fFramesSent)
					/ double(fOutput.format.u.raw_audio.frame_rate)
					* 1000000.0);
				media_timed_event nextBufferEvent(nextEvent,
					BTimedEventQueue::B_HANDLE_BUFFER);
				EventQueue()->AddEvent(nextBufferEvent);
			}
		}
		break;

	default:
		break;
	}
}
Beispiel #23
0
// how should we handle late buffers?  drop them?
// notify the producer?
status_t
SoundPlayNode::SendNewBuffer(const media_timed_event* event,
	bigtime_t lateness, bool realTimeEvent)
{
	CALLED();
	// printf("latency = %12Ld, event = %12Ld, sched = %5Ld, arrive at %12Ld, now %12Ld, current lateness %12Ld\n", EventLatency() + SchedulingLatency(), EventLatency(), SchedulingLatency(), event->event_time, TimeSource()->Now(), lateness);

	// make sure we're both started *and* connected before delivering a buffer
	if (RunState() != BMediaEventLooper::B_STARTED
		|| fOutput.destination == media_destination::null)
		return B_OK;

	// The event->event_time is the time at which the buffer we are preparing
	// here should arrive at it's destination. The MediaEventLooper should have
	// scheduled us early enough (based on EventLatency() and the
	// SchedulingLatency()) to make this possible.
	// lateness is independent of EventLatency()!

	if (lateness > (BufferDuration() / 3) ) {
		printf("SoundPlayNode::SendNewBuffer, event scheduled much too late, "
			"lateness is %Ld\n", lateness);
	}

	// skip buffer creation if output not enabled
	if (fOutputEnabled) {

		// Get the next buffer of data
		BBuffer* buffer = FillNextBuffer(event->event_time);

		if (buffer) {

			// If we are ready way too early, decrase internal latency
/*
			bigtime_t how_early = event->event_time - TimeSource()->Now() - fLatency - fInternalLatency;
			if (how_early > 5000) {

				printf("SoundPlayNode::SendNewBuffer, event scheduled too early, how_early is %Ld\n", how_early);

				if (fTooEarlyCount++ == 5) {
					fInternalLatency -= how_early;
					if (fInternalLatency < 500)
						fInternalLatency = 500;
					printf("SoundPlayNode::SendNewBuffer setting internal latency to %Ld\n", fInternalLatency);
					SetEventLatency(fLatency + fInternalLatency);
					fTooEarlyCount = 0;
				}
			}
*/
			// send the buffer downstream if and only if output is enabled
			if (SendBuffer(buffer, fOutput.source, fOutput.destination)
					!= B_OK) {
				// we need to recycle the buffer
				// if the call to SendBuffer() fails
				printf("SoundPlayNode::SendNewBuffer: Buffer sending "
					"failed\n");
				buffer->Recycle();
			}
		}
	}

	// track how much media we've delivered so far
	size_t nFrames = fOutput.format.u.raw_audio.buffer_size
		/ ((fOutput.format.u.raw_audio.format
			& media_raw_audio_format::B_AUDIO_SIZE_MASK)
		* fOutput.format.u.raw_audio.channel_count);
	fFramesSent += nFrames;

	// The buffer is on its way; now schedule the next one to go
	// nextEvent is the time at which the buffer should arrive at it's
	// destination
	bigtime_t nextEvent = fStartTime + bigtime_t((1000000LL * fFramesSent)
		/ (int32)fOutput.format.u.raw_audio.frame_rate);
	media_timed_event nextBufferEvent(nextEvent, SEND_NEW_BUFFER_EVENT);
	EventQueue()->AddEvent(nextBufferEvent);

	return B_OK;
}
Beispiel #24
0
status_t
BBufferConsumer::HandleMessage(int32 message, const void* data, size_t size)
{
	PRINT(4, "BBufferConsumer::HandleMessage %#lx, node %ld\n", message, ID());
	status_t rv;
	switch (message) {
		case CONSUMER_ACCEPT_FORMAT:
		{
			const consumer_accept_format_request* request
				= static_cast<const consumer_accept_format_request*>(data);

			consumer_accept_format_reply reply;
			reply.format = request->format;
			status_t status = AcceptFormat(request->dest, &reply.format);
			request->SendReply(status, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_GET_NEXT_INPUT:
		{
			const consumer_get_next_input_request *request = static_cast<const consumer_get_next_input_request *>(data);
			consumer_get_next_input_reply reply;
			reply.cookie = request->cookie;
			rv = GetNextInput(&reply.cookie, &reply.input);
			request->SendReply(rv, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_DISPOSE_INPUT_COOKIE:
		{
			const consumer_dispose_input_cookie_request *request = static_cast<const consumer_dispose_input_cookie_request *>(data);
			consumer_dispose_input_cookie_reply reply;
			DisposeInputCookie(request->cookie);
			request->SendReply(B_OK, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_BUFFER_RECEIVED:
		{
			const consumer_buffer_received_command* command
				= static_cast<const consumer_buffer_received_command*>(data);

			BBuffer* buffer = fBufferCache->GetBuffer(command->buffer);
			if (buffer == NULL) {
				ERROR("BBufferConsumer::CONSUMER_BUFFER_RECEIVED can't"
					"find the buffer\n");
			} else {
				buffer->SetHeader(&command->header);

				PRINT(4, "calling BBufferConsumer::BufferReceived buffer %ld "
					"at perf %Ld and TimeSource()->Now() is %Ld\n",
					buffer->Header()->buffer, buffer->Header()->start_time,
					TimeSource()->Now());

				BufferReceived(buffer);
			}
			return B_OK;
		}

		case CONSUMER_PRODUCER_DATA_STATUS:
		{
			const consumer_producer_data_status_command *command = static_cast<const consumer_producer_data_status_command *>(data);
			ProducerDataStatus(command->for_whom, command->status, command->at_performance_time);
			return B_OK;
		}

		case CONSUMER_GET_LATENCY_FOR:
		{
			const consumer_get_latency_for_request *request = static_cast<const consumer_get_latency_for_request *>(data);
			consumer_get_latency_for_reply reply;
			rv = GetLatencyFor(request->for_whom, &reply.latency, &reply.timesource);
			request->SendReply(rv, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_CONNECTED:
		{
			const consumer_connected_request *request = static_cast<const consumer_connected_request *>(data);
			consumer_connected_reply reply;
			reply.input = request->input;
			rv = Connected(request->input.source, request->input.destination, request->input.format, &reply.input);
			request->SendReply(rv, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_DISCONNECTED:
		{
			const consumer_disconnected_request *request = static_cast<const consumer_disconnected_request *>(data);
			consumer_disconnected_reply reply;
			Disconnected(request->source, request->destination);
			request->SendReply(B_OK, &reply, sizeof(reply));
			return B_OK;
		}

		case CONSUMER_FORMAT_CHANGED:
		{
			const consumer_format_changed_request *request = static_cast<const consumer_format_changed_request *>(data);
			consumer_format_changed_reply reply;
			rv = FormatChanged(request->producer, request->consumer, request->change_tag, request->format);
			request->SendReply(rv, &reply, sizeof(reply));

			// XXX is this RequestCompleted() correct?
			node_request_completed_command completedcommand;
			completedcommand.info.what = media_request_info::B_FORMAT_CHANGED;
			completedcommand.info.change_tag = request->change_tag;
			completedcommand.info.status = reply.result;
			//completedcommand.info.cookie
			completedcommand.info.user_data = 0;
			completedcommand.info.source = request->producer;
			completedcommand.info.destination = request->consumer;
			completedcommand.info.format = request->format;
			SendToPort(request->consumer.port, NODE_REQUEST_COMPLETED, &completedcommand, sizeof(completedcommand));
			return B_OK;
		}

		case CONSUMER_SEEK_TAG_REQUESTED:
		{
			const consumer_seek_tag_requested_request *request = static_cast<const consumer_seek_tag_requested_request *>(data);
			consumer_seek_tag_requested_reply reply;
			rv = SeekTagRequested(request->destination, request->target_time, request->flags, &reply.seek_tag, &reply.tagged_time, &reply.flags);
			request->SendReply(rv, &reply, sizeof(reply));
			return B_OK;
		}
	}
	return B_ERROR;
}
Beispiel #25
0
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?
}
int32
VideoProducer::_FrameGeneratorThread()
{
	bool forceSendingBuffer = true;
	int32 droppedFrames = 0;
	const int32 kMaxDroppedFrames = 15;
	bool running = true;
	while (running) {
		TRACE("_FrameGeneratorThread: loop: %Ld\n", fFrame);
		// lock the node manager
		status_t err = fManager->LockWithTimeout(10000);
		bool ignoreEvent = false;
		// Data to be retrieved from the node manager.
		bigtime_t performanceTime = 0;
		bigtime_t nextPerformanceTime = 0;
		bigtime_t waitUntil = 0;
		bigtime_t nextWaitUntil = 0;
		int32 playingDirection = 0;
		int32 playingMode = 0;
		int64 playlistFrame = 0;
		switch (err) {
			case B_OK: {
				TRACE("_FrameGeneratorThread: node manager successfully "
					"locked\n");
				if (droppedFrames > 0)
					fManager->FrameDropped();
				// get the times for the current and the next frame
				performanceTime = fManager->TimeForFrame(fFrame);
				nextPerformanceTime = fManager->TimeForFrame(fFrame + 1);
				playingMode = fManager->PlayModeAtFrame(fFrame);
				waitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase
					+ performanceTime, fBufferLatency);
				nextWaitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase
					+ nextPerformanceTime, fBufferLatency);
				// get playing direction and playlist frame for the current
				// frame
				bool newPlayingState;
				playlistFrame = fManager->PlaylistFrameAtFrame(fFrame,
					playingDirection, newPlayingState);
				TRACE("_FrameGeneratorThread: performance time: %Ld, "
					"playlist frame: %lld\n", performanceTime, playlistFrame);
				forceSendingBuffer |= newPlayingState;
				fManager->SetCurrentVideoTime(nextPerformanceTime);
				fManager->Unlock();
				break;
			}
			case B_TIMED_OUT:
				TRACE("_FrameGeneratorThread: Couldn't lock the node "
					"manager.\n");
				ignoreEvent = true;
				waitUntil = system_time() - 1;
				break;
			default:
				ERROR("_FrameGeneratorThread: Couldn't lock the node manager. "
					"Terminating video producer frame generator thread.\n");
				TRACE("_FrameGeneratorThread: frame generator thread done.\n");
				// do not access any member variables, since this could
				// also mean the Node has been deleted
				return B_OK;
		}

		TRACE("_FrameGeneratorThread: waiting (%Ld)...\n", waitUntil);
		// wait until...
		err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, waitUntil);
		// The only acceptable responses are B_OK and B_TIMED_OUT. Everything
		// else means the thread should quit. Deleting the semaphore, as in
		// VideoProducer::_HandleStop(), will trigger this behavior.
		switch (err) {
			case B_OK:
				TRACE("_FrameGeneratorThread: going back to sleep.\n");
				break;
			case B_TIMED_OUT:
				TRACE("_FrameGeneratorThread: timed out => event\n");
				// Catch the cases in which the node manager could not be
				// locked and we therefore have no valid data to work with,
				// or the producer is not running or enabled.
				if (ignoreEvent || !fRunning || !fEnabled) {
					TRACE("_FrameGeneratorThread: ignore event\n");
					// nothing to do
				} else if (!forceSendingBuffer
					&& nextWaitUntil < system_time() - fBufferLatency
					&& droppedFrames < kMaxDroppedFrames) {
					// Drop frame if it's at least a frame late.
					if (playingDirection > 0)
						printf("VideoProducer: dropped frame (%Ld)\n", fFrame);
					// next frame
					droppedFrames++;
					fFrame++;
				} else if (playingDirection != 0 || forceSendingBuffer) {
					// Send buffers only, if playing, the node is running and
					// the output has been enabled
					TRACE("_FrameGeneratorThread: produce frame\n");
					BAutolock _(fLock);
					// Fetch a buffer from the buffer group
					fUsedBufferGroup->WaitForBuffers();
					BBuffer* buffer = fUsedBufferGroup->RequestBuffer(
						fConnectedFormat.display.bytes_per_row
						* fConnectedFormat.display.line_count, 0LL);
					if (buffer == NULL) {
						// Wait until a buffer becomes available again
						ERROR("_FrameGeneratorThread: no buffer!\n");
						break;
					}
					// Fill out the details about this buffer.
					media_header* h = buffer->Header();
					h->type = B_MEDIA_RAW_VIDEO;
					h->time_source = TimeSource()->ID();
					h->size_used = fConnectedFormat.display.bytes_per_row
						* fConnectedFormat.display.line_count;
					// For a buffer originating from a device, you might
					// want to calculate this based on the
					// PerformanceTimeFor the time your buffer arrived at
					// the hardware (plus any applicable adjustments).
					h->start_time = fPerformanceTimeBase + performanceTime;
					h->file_pos = 0;
					h->orig_size = 0;
					h->data_offset = 0;
					h->u.raw_video.field_gamma = 1.0;
					h->u.raw_video.field_sequence = fFrame;
					h->u.raw_video.field_number = 0;
					h->u.raw_video.pulldown_number = 0;
					h->u.raw_video.first_active_line = 1;
					h->u.raw_video.line_count
						= fConnectedFormat.display.line_count;
					// Fill in a frame
					TRACE("_FrameGeneratorThread: frame: %Ld, "
						"playlistFrame: %Ld\n", fFrame, playlistFrame);
					bool wasCached = false;
					err = fSupplier->FillBuffer(playlistFrame,
						buffer->Data(), fConnectedFormat, forceSendingBuffer,
						wasCached);
					if (err == B_TIMED_OUT) {
						// Don't send the buffer if there was insufficient
						// time for rendering, this will leave the last
						// valid frame on screen until we catch up, instead
						// of going black.
						wasCached = true;
						err = B_OK;
					}
					// clean the buffer if something went wrong
					if (err != B_OK) {
						// TODO: should use "back value" according
						// to color space!
						memset(buffer->Data(), 0, h->size_used);
						err = B_OK;
					}
					// Send the buffer on down to the consumer
					if (wasCached || (err = SendBuffer(buffer, fOutput.source,
							fOutput.destination) != B_OK)) {
						// If there is a problem sending the buffer,
						// or if we don't send the buffer because its
						// contents are the same as the last one,
						// return it to its buffer group.
						buffer->Recycle();
						// we tell the supplier to delete
						// its caches if there was a problem sending
						// the buffer
						if (err != B_OK) {
							ERROR("_FrameGeneratorThread: Error "
								"sending buffer\n");
							fSupplier->DeleteCaches();
						}
					}
					// Only if everything went fine we clear the flag
					// that forces us to send a buffer even if not
					// playing.
					if (err == B_OK)
						forceSendingBuffer = false;
					// next frame
					fFrame++;
					droppedFrames = 0;
				} else {
					TRACE("_FrameGeneratorThread: not playing\n");
					// next frame
					fFrame++;
				}
				break;
			default:
				TRACE("_FrameGeneratorThread: Couldn't acquire semaphore. "
					"Error: %s\n", strerror(err));
				running = false;
				break;
		}
	}
	TRACE("_FrameGeneratorThread: frame generator thread done.\n");
	return B_OK;
}
Beispiel #27
0
BBuffer*
ToneProducer::FillNextBuffer(bigtime_t event_time)
{
	// get a buffer from our buffer group
	BBuffer* buf = mBufferGroup->RequestBuffer(mOutput.format.u.raw_audio.buffer_size, BufferDuration());

	// if we fail to get a buffer (for example, if the request times out), we skip this
	// buffer and go on to the next, to avoid locking up the control thread
	if (!buf)
	{
		return NULL;
	}

	// now fill it with data, continuing where the last buffer left off
	// 20sep99: multichannel support

	size_t numFrames =
		mOutput.format.u.raw_audio.buffer_size /
		(sizeof(float)*mOutput.format.u.raw_audio.channel_count);
	bool stereo = (mOutput.format.u.raw_audio.channel_count == 2);
	if(!stereo) {
		ASSERT(mOutput.format.u.raw_audio.channel_count == 1);
	}
//	PRINT(("buffer: %ld, %ld frames, %s\n", mOutput.format.u.raw_audio.buffer_size, numFrames, stereo ? "stereo" : "mono"));

	float* data = (float*) buf->Data();

	switch (mWaveform)
	{
	case SINE_WAVE:
		FillSineBuffer(data, numFrames, stereo);
		break;

	case TRIANGLE_WAVE:
		FillTriangleBuffer(data, numFrames, stereo);
		break;

	case SAWTOOTH_WAVE:
		FillSawtoothBuffer(data, numFrames, stereo);
		break;
	}

	// fill in the buffer header
	media_header* hdr = buf->Header();
	hdr->type = B_MEDIA_RAW_AUDIO;
	hdr->size_used = mOutput.format.u.raw_audio.buffer_size;
	hdr->time_source = TimeSource()->ID();

	bigtime_t stamp;
	if (RunMode() == B_RECORDING)
	{
		// In B_RECORDING mode, we stamp with the capture time.  We're not
		// really a hardware capture node, but we simulate it by using the (precalculated)
		// time at which this buffer "should" have been created.
		stamp = event_time;
	}
	else
	{
		// okay, we're in one of the "live" performance run modes.  in these modes, we
		// stamp the buffer with the time at which the buffer should be rendered to the
		// output, not with the capture time.  mStartTime is the cached value of the
		// first buffer's performance time; we calculate this buffer's performance time as
		// an offset from that time, based on the amount of media we've created so far.
		// Recalculating every buffer like this avoids accumulation of error.
		stamp = mStartTime + bigtime_t(double(mFramesSent) / double(mOutput.format.u.raw_audio.frame_rate) * 1000000.0);
	}
	hdr->start_time = stamp;

	return buf;
}
Beispiel #28
0
void
ToneProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, bool realTimeEvent)
{
//	FPRINTF(stderr, "ToneProducer::HandleEvent\n");
	switch (event->type)
	{
	case BTimedEventQueue::B_START:
		// don't do anything if we're already running
		if (RunState() != B_STARTED)
		{
			// We want to start sending buffers now, so we set up the buffer-sending bookkeeping
			// and fire off the first "produce a buffer" event.
			mFramesSent = 0;
			mTheta = 0;
			mStartTime = event->event_time;
			media_timed_event firstBufferEvent(mStartTime, BTimedEventQueue::B_HANDLE_BUFFER);

			// Alternatively, we could call HandleEvent() directly with this event, to avoid a trip through
			// the event queue, like this:
			//
			//		this->HandleEvent(&firstBufferEvent, 0, false);
			//
			EventQueue()->AddEvent(firstBufferEvent);
		}
		break;

	case BTimedEventQueue::B_STOP:
		FPRINTF(stderr, "Handling B_STOP event\n");

		// When we handle a stop, we must ensure that downstream consumers don't
		// get any more buffers from us.  This means we have to flush any pending
		// buffer-producing events from the queue.
		EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
		break;

	case _PARAMETER_EVENT:
		{
			size_t dataSize = size_t(event->data);
			int32 param = int32(event->bigdata);
			if (dataSize >= sizeof(float)) switch (param)
			{
			case FREQUENCY_PARAM:
				{
					float newValue = *((float*) event->user_data);
					if (mFrequency != newValue)		// an actual change in the value?
					{
						mFrequency = newValue;
						mFreqLastChanged = TimeSource()->Now();
						BroadcastNewParameterValue(mFreqLastChanged, param, &mFrequency, sizeof(mFrequency));
					}
				}
				break;

			case GAIN_PARAM:
				{
					float newValue = *((float*) event->user_data);
					if (mGain != newValue)
					{
						mGain = newValue;
						mGainLastChanged = TimeSource()->Now();
						BroadcastNewParameterValue(mGainLastChanged, param, &mGain, sizeof(mGain));
					}
				}
				break;

			case WAVEFORM_PARAM:
				{
					int32 newValue = *((int32*) event->user_data);
					if (mWaveform != newValue)
					{
						mWaveform = newValue;
						mTheta = 0;			// reset the generator parameters when we change waveforms
						mWaveAscending = true;
						mWaveLastChanged = TimeSource()->Now();
						BroadcastNewParameterValue(mWaveLastChanged, param, &mWaveform, sizeof(mWaveform));
					}
				}
				break;

			default:
				FPRINTF(stderr, "Hmmm... got a B_PARAMETER event for a parameter we don't have? (%" B_PRId32 ")\n", param);
				break;
			}
		}
		break;

	case BTimedEventQueue::B_HANDLE_BUFFER:
		{
			// make sure we're both started *and* connected before delivering a buffer
			if (RunState() == BMediaEventLooper::B_STARTED
				&& mOutput.destination != media_destination::null) {
				// Get the next buffer of data
				BBuffer* buffer = FillNextBuffer(event->event_time);
				if (buffer) {
					// send the buffer downstream if and only if output is enabled
					status_t err = B_ERROR;
					if (mOutputEnabled) {
						err = SendBuffer(buffer, mOutput.source,
							mOutput.destination);
					}
					if (err) {
						// we need to recycle the buffer ourselves if output is disabled or
						// if the call to SendBuffer() fails
						buffer->Recycle();
					}
				}

				// track how much media we've delivered so far
				size_t nFrames = mOutput.format.u.raw_audio.buffer_size /
					(sizeof(float) * mOutput.format.u.raw_audio.channel_count);
				mFramesSent += nFrames;

				// The buffer is on its way; now schedule the next one to go
				bigtime_t nextEvent = mStartTime + bigtime_t(double(mFramesSent)
					/ double(mOutput.format.u.raw_audio.frame_rate) * 1000000.0);
				media_timed_event nextBufferEvent(nextEvent,
					BTimedEventQueue::B_HANDLE_BUFFER);
				EventQueue()->AddEvent(nextBufferEvent);
			}
		}
		break;

	default:
		break;
	}
}
Beispiel #29
0
// create or discard buffer group if necessary
void AudioFilterNode::updateBufferGroup() {

	status_t err;
	
	size_t inputSize = bytes_per_frame(m_input.format.u.raw_audio);
	size_t outputSize = bytes_per_frame(m_output.format.u.raw_audio);
	
	if(m_input.source == media_source::null ||
		m_output.destination == media_destination::null ||
		inputSize >= outputSize) {

		PRINT(("###### NO BUFFER GROUP NEEDED\n"));
		
		// no internal buffer group needed
		if(m_bufferGroup) {
			// does this block? +++++
			delete m_bufferGroup;
			m_bufferGroup = 0;
		}
		return;
	}
	
	int32 bufferCount = EventLatency() / BufferDuration() + 1 + 1;
	
	// +++++
	// [e.moon 27sep99] this is a reasonable number of buffers,
	// but it fails with looped file-player node in BeOS 4.5.2.
	//
	if(bufferCount < 5)
		bufferCount = 5;
//	if(bufferCount < 3)
//		bufferCount = 3;
		
	if(m_bufferGroup) {

		// is the current group sufficient?
		int32 curBufferCount;
		err = m_bufferGroup->CountBuffers(&curBufferCount);
		if(err == B_OK && curBufferCount >= bufferCount) {		
			BBuffer* buf = m_bufferGroup->RequestBuffer(
				outputSize, -1);
		
			if(buf) {
				// yup
				buf->Recycle();
				return;
			}
		}

		// nope, delete it to make way for the new one
		delete m_bufferGroup;
		m_bufferGroup = 0;		
	}
	
	// create buffer group
	PRINT((
		"##### AudioFilterNode::updateBufferGroup():\n"
		"##### creating %ld buffers of size %ld\n",
		bufferCount, m_output.format.u.raw_audio.buffer_size));

	m_bufferGroup = new BBufferGroup(
		m_output.format.u.raw_audio.buffer_size,
		bufferCount);
}
Beispiel #30
0
void AudioFilterNode::BufferReceived(
	BBuffer*										buffer) {
	ASSERT(buffer);

	// check buffer destination
	if(buffer->Header()->destination !=
		m_input.destination.id) {
		PRINT(("AudioFilterNode::BufferReceived():\n"
			"\tBad destination.\n"));
		buffer->Recycle();
		return;
	}
	
	if(buffer->Header()->time_source != TimeSource()->ID()) { // +++++ no-go in offline mode
		PRINT(("* timesource mismatch\n"));
	}

	// check output
	if(m_output.destination == media_destination::null ||
		!m_outputEnabled) {
		buffer->Recycle();
		return;
	}
	
//	// +++++ [9sep99]
//	bigtime_t now = TimeSource()->Now();
//	bigtime_t delta = now - m_tpLastReceived;
//	m_tpLastReceived = now;
//	PRINT((
//		"### delta: %Ld (%Ld)\n",
//		delta, buffer->Header()->start_time - now));

	// fetch outbound buffer if needed
	BBuffer* outBuffer;
	if(m_bufferGroup) {
		outBuffer = m_bufferGroup->RequestBuffer(
			m_output.format.u.raw_audio.buffer_size, -1);
		ASSERT(outBuffer);
		
		// prepare outbound buffer
		outBuffer->Header()->type = B_MEDIA_RAW_AUDIO;

		// copy start time info from upstream node
		// +++++ is this proper, or should the next buffer-start be
		//       continuously tracked (figured from Start() or the first
		//       buffer received?)
		outBuffer->Header()->time_source = buffer->Header()->time_source;
		outBuffer->Header()->start_time = buffer->Header()->start_time;
	}
	else {
		// process inplace
		outBuffer = buffer;
	}
			
	// process and retransmit buffer
	processBuffer(buffer, outBuffer);

	status_t err = SendBuffer(outBuffer, m_output.source, m_output.destination);
	if (err < B_OK) {
		PRINT(("AudioFilterNode::BufferReceived():\n"
			"\tSendBuffer() failed: %s\n", strerror(err)));
		outBuffer->Recycle();
	}

	// free inbound buffer if data was copied	
	if(buffer != outBuffer)
		buffer->Recycle();

//	//####resend
//	SendBuffer(buffer, m_output.destination);

	// sent!
}