⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soundconsumer.cxx

📁 基于VXWORKS H323通信技术源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
		return B_MEDIA_BAD_FORMAT;
	}
#if !ACCEPT_ANY_FORMAT_CHANGE
	//	If we're already connected, and this format doesn't go with the
	//	format in effect, we dont' accept this new format.
	if (!format_is_compatible(*format, m_input.format)) {
		*format = m_input.format;
		return B_MEDIA_BAD_FORMAT;
	}
#endif
	//	I guess we're OK by now, because we have no particular needs as
	//	far as frame rate, sample format, etc go.
	return B_OK;
}


status_t SoundConsumer::GetNextInput(
	int32 * cookie,
	media_input * out_input)
{
	NODE(stderr, "SoundConsumer: GetNextInput()\n");
	//	The "next" is kind of misleading, since it's also used for
	//	getting the first (and only) input.
	if (!*cookie) {
		if (m_input.source == media_source::null) {
			//	If there's no current connection, make sure we return a
			//	reasonable format telling the world we accept any raw audio.
			m_input.format.type = B_MEDIA_RAW_AUDIO;
			m_input.format.u.raw_audio = media_raw_audio_format::wildcard;
			m_input.node = Node();
			m_input.destination.port = ControlPort();
			m_input.destination.id = 1;
		}
		*out_input = m_input;
		*cookie = 1;
		return B_OK;
	}
	//	There's only one input.
	return B_BAD_INDEX;
}


void SoundConsumer::DisposeInputCookie(
	int32 /* cookie */)
{
	//	We didn't allocate any memory or set any state in GetNextInput()
	//	so this function is a no-op.
}


void SoundConsumer::BufferReceived(
	BBuffer * buffer)
{
	NODE(stderr, "SoundConsumer::BufferReceived()\n");
	//	Whee, a buffer! Update the seek info, if necessary.
	if (m_seeking && buffer->Header()->start_time >= m_tpSeekAt) {
		m_delta = m_tpSeekAt - m_tmSeekTo;
		m_seeking = false;
	}
	//	If there is a record hook, let the interested party have at it!
	if (m_recordHook) {
		(*m_recordHook)(m_cookie, buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_input.format.u.raw_audio);
	}
	else {
		Record(buffer->Header()->start_time-m_delta, buffer->Data(), buffer->Header()->size_used, m_input.format.u.raw_audio);
	}
	//	Buffers should ALWAYS be recycled, else whomever is producing them
	//	will starve.
	buffer->Recycle();
}


void SoundConsumer::ProducerDataStatus(
	const media_destination & for_whom,
	int32 status,
	bigtime_t at_media_time)
{
	if (for_whom == m_input.destination) {
		//	Tell whomever is interested that the upstream producer will or won't
		//	send more data in the immediate future.
		if (m_notifyHook) {
			(*m_notifyHook)(m_cookie, B_PRODUCER_DATA_STATUS, status, at_media_time);
		}
		else {
			Notify(B_PRODUCER_DATA_STATUS, status, at_media_time);
		}
	}
}


status_t SoundConsumer::GetLatencyFor(
	const media_destination & for_whom,
	bigtime_t * out_latency,
	media_node_id * out_timesource)
{
	//	We only accept requests for the one-and-only input of our Node.
	if (for_whom != m_input.destination) {
		return B_MEDIA_BAD_DESTINATION;
	}
	//	Tell the world about our latency information (overridable by user).
	*out_latency = TotalLatency();
	*out_timesource = TimeSource()->Node().node;
	return B_OK;
}


status_t SoundConsumer::Connected(
	const media_source & producer,
	const media_destination & where,
	const media_format & with_format,
	media_input * out_input)
{
	NODE(stderr, "SoundConsumer::Connected()\n");
	//	Only accept connection requests when we're not already connected.
	if (m_input.source != media_source::null) {
		return B_MEDIA_BAD_DESTINATION;
	}
	//	Only accept connection requests on the one-and-only available input.
	if (where != m_input.destination) {
		return B_MEDIA_BAD_DESTINATION;
	}
	//	Other than that, we accept pretty much anything. The format has been
	//	pre-cleared through AcceptFormat(), and we accept any format anyway.
	m_input.source = producer;
	m_input.format = with_format;
	//	Tell whomever is interested that there's now a connection.
	if (m_notifyHook) {
		(*m_notifyHook)(m_cookie, B_CONNECTED, m_input.name);
	}
	else {
		Notify(B_CONNECTED, m_input.name);
	}
	//	This is the most important line -- return our connection information
	//	to the world so it can use it!
	*out_input = m_input;
	return B_OK;
}


void SoundConsumer::Disconnected(
	const media_source & producer,
	const media_destination & where)
{
	//	We can't disconnect something which isn't us.
	if (where != m_input.destination) {
		return;
	}
	//	We can't disconnect from someone who isn't connected to us.
	if (producer != m_input.source) {
		return;
	}
	//	Tell the interested party that it's time to leave.
	if (m_notifyHook) {
		(*m_notifyHook)(m_cookie, B_DISCONNECTED);
	}
	else {
		Notify(B_DISCONNECTED);
	}
	//	Mark ourselves as not-connected.
	m_input.source = media_source::null;
}


status_t SoundConsumer::FormatChanged(
	const media_source & producer,
	const media_destination & consumer, 
	int32 from_change_count,
	const media_format & format)
{
	NODE(stderr, "SoundConsumer::Connected()\n");
	//	The up-stream guy feels like changing the format. If we can accept
	//	arbitrary format changes, we just say "OK". If, however, we're recording
	//	to a file, that's not such a good idea; we only accept format changes
	//	that are compatible with the format we're already using. You set this
	//	behaviour at compile time by defining ACCEPT_ANY_FORMAT_CHANGE to 1 or 0.
	status_t err = B_OK;
#if ACCEPT_ANY_FORMAT_CHANGE
	media_format fmt(format);
	err = AcceptFormat(m_input.destination, &fmt);
#else
	if (m_input.source != media_source::null) {
		err = format_is_compatible(format, m_input.format) ? B_OK : B_MEDIA_BAD_FORMAT;
	}
#endif
	if (err >= B_OK) {
		m_input.format = format;
		if (m_notifyHook) {
			(*m_notifyHook)(m_cookie, B_FORMAT_CHANGED, &m_input.format.u.raw_audio);
		}
		else {
			Notify(B_FORMAT_CHANGED, &m_input.format.u.raw_audio);
		}
	}
	return err;
}


void
SoundConsumer::DoHookChange(
	void * msg)
{
	//	Tell the old guy we're changing the hooks ...
	if (m_notifyHook) {
		(*m_notifyHook)(m_cookie, B_HOOKS_CHANGED);
	}
	else {
		Notify(B_HOOKS_CHANGED);
	}
	//	... and then do it.
	set_hooks_q * ptr = (set_hooks_q *)msg;
	m_recordHook = ptr->process;
	m_notifyHook = ptr->notify;
	m_cookie = ptr->cookie;
}


status_t
SoundConsumer::ThreadEntry(
	void * obj)
{
	((SoundConsumer *)obj)->ServiceThread();
	return 0;
}


void
SoundConsumer::ServiceThread()
{
	//	The Big Bad ServiceThread receives messages aimed at this
	//	Node and dispatches them (typically to HandleMessage()).
	//	If we were a Producer, we might have to do finicky timing and
	//	queued Start()/Stop() processing in here. But we ain't.

	//	A media kit message will never be bigger than B_MEDIA_MESSAGE_SIZE.
	//	Avoid wasing stack space by dynamically allocating at start.
	char * msg = new char[B_MEDIA_MESSAGE_SIZE];
	//	Make sure we clean up this data when we exit the function.
	array_delete<char> msg_delete(msg);
	int bad = 0;
	while (true) {
		//	Call read_port_etc() with a timeout derived from a virtual function,
		//	to allow clients to do special processing if necessary.
		bigtime_t timeout = Timeout();
		int32 code = 0;
		status_t err = read_port_etc(m_port, &code, msg, B_MEDIA_MESSAGE_SIZE,
			B_TIMEOUT, timeout);
		MESSAGE(stderr, "SoundConsumer::ServiceThread() port %ld message %#010lx\n", m_port, code);
		//	If we received a message, err will be the size of the message (including 0).
		if (err >= 0) {
			//	Real messages reset the timeout time.
			m_trTimeout = 0;
			bad = 0;
			//	Check for our private stop message.
			if (code == MSG_QUIT_NOW) {
				if (m_notifyHook) {
					(*m_notifyHook)(m_cookie, B_NODE_DIES, 0);
				}
				else {
					Notify(B_NODE_DIES, 0);
				}
				break;
			}
			//	Else check for our private change-hooks message.
			else if (code == MSG_CHANGE_HOOKS) {
				DoHookChange(msg);
				//	Write acknowledge to waiting thread.
				write_port(((set_hooks_q *)msg)->reply, 0, 0, 0);
			}
			//	Else it has to be a regular media kit message; go ahead and
			//	dispatch it.
			else {
				HandleMessage(code, msg, err);
			}
		}
		//	Timing out means that there was no buffer. Tell the interested party.
		else if (err == B_TIMED_OUT) {
			if (m_notifyHook) {
				(*m_notifyHook)(m_cookie, B_OP_TIMED_OUT, timeout);
			}
			else {
				Notify(B_OP_TIMED_OUT, timeout);
			}
		}
		//	Other errors are bad.
		else {
			FPRINTF(stderr, "SoundConsumer: error %#010lx\n", err);
			bad++;
			//	If we receive three bad reads with no good messages inbetween,
			//	things are probably not going to improve (like the port disappeared
			//	or something) so we call it a day.
			if (bad > 3) {
				if (m_notifyHook) {
					(*m_notifyHook)(m_cookie, B_NODE_DIES, bad, err, code, msg);
				}
				else {
					Notify(B_NODE_DIES, bad, err, code, msg);
				}
				break;
			}
		}
	}
}


bigtime_t
SoundConsumer::Timeout()
{
	//	Timeout() is called for each call to read_port_etc() in the service
	//	thread to figure out a reasonable time-out value. The default behaviour
	//	we've picked is to exponentially back off from one second and upwards.
	//	While it's true that 44 back-offs will run us out of precision in a
	//	bigtime_t, the time to actually reach 44 consecutive back-offs is longer
	//	than the expected market longevity of just about any piece of real estate.
	//	Is that the sound of an impending year-fifteen-million software problem? :-)
	m_trTimeout = (m_trTimeout < 1000000) ? 1000000 : m_trTimeout*2;
	return m_trTimeout;
}


bigtime_t
SoundConsumer::ProcessingLatency()
{
	//	We're saying it takes us 500 us to process each buffer. If all we do is
	//	copy the data, it probably takes much less than that, but it doesn't
	//	hurt to be slightly conservative. 
	return 500LL;
}


bigtime_t
SoundConsumer::TotalLatency()
{
	//	Had we been a producer that passes buffers on, we'd have to
	//	include downstream latency in this value. But we are not.
	return ProcessingLatency();
}

void
SoundConsumer::Record(
	bigtime_t /* time */,
	const void * /* data */,
	size_t /* size */,
	const media_raw_audio_format & /* format */)
{
	//	If there is no record hook installed, we instead call this function
	//	for received buffers.
}


void
SoundConsumer::Notify(
	int32 /* cause */,
	...)
{
	//	If there is no notification hook installed, we instead call this function
	//	for giving notification of various events.
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -