<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Scansoft</TITLE>
<META content="text/html; charset=us-ascii" http-equiv=Content-Type>
<META name=GENERATOR content="MSHTML 9.00.8112.16440"></HEAD>
<BODY
style="BACKGROUND-COLOR: #e0e0e0; FONT-FAMILY: Trebuchet MS; COLOR: #005080; FONT-SIZE: 10pt"
background="" bgColor=#e0e0e0>
<DIV><SPAN class=867540013-14022012>Good afternoon,</SPAN></DIV>
<DIV><SPAN class=867540013-14022012></SPAN> </DIV>
<DIV><SPAN class=867540013-14022012>As a second post to this list, I have to
thank you for your first advice, I was definitely using the wrong testProg to
start with. I have since reworked the testRTSPClient code to function in the
fashion that I wish, but still cannot get both subsessions to provide data to
me. Allow me to explain my use-case:</SPAN></DIV>
<DIV><SPAN class=867540013-14022012></SPAN> </DIV>
<DIV><SPAN class=867540013-14022012>I am trying to obtain the audio/video stream
from a Vivotek IP camera (FD8161), so far I can obtain either the video stream
(by supplying a flag stating that I only want to create the video or audio sink)
or the audio stream perfectly. The moment I try to create two sinks to handle
the data from each subsession, then I fail to get data passed to me in the
afterGettingFrame function of my custom sinks. I know the sinks should be
working fine since it works individually, I will provide the snippet of code
which assigns the sinks to their respective subsessions, this snippet is what
I've modified to create seperate sinks for audio and video data:</SPAN></DIV>
<DIV><SPAN class=867540013-14022012></SPAN> </DIV>
<DIV><SPAN class=867540013-14022012>...</SPAN></DIV>
<DIV><SPAN class=867540013-14022012>void SetupStreams()</SPAN></DIV>
<DIV><SPAN class=867540013-14022012>{</SPAN></DIV>
<DIV><SPAN class=867540013-14022012>
<P><FONT color=#0000ff><FONT color=#0000ff>static</FONT></FONT>
MediaSubsessionIterator* setupIter = NULL;</P>
<P></P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_session ==
NULL)</P>
<P>{</P>
<P>Shutdown();</P>
<P><FONT color=#0000ff><FONT color=#0000ff>return</FONT></FONT>;</P>
<P>}</P>
<P></P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (setupIter ==
NULL)</P>
<P>setupIter = <FONT color=#0000ff><FONT color=#0000ff>new</FONT></FONT>
MediaSubsessionIterator(*g_session);</P>
<P><FONT color=#0000ff><FONT color=#0000ff>while</FONT></FONT>
((g_setupSubsession = setupIter->next()) != NULL) </P>
<P>{</P>
<P><FONT color=#008000><FONT color=#008000>// We have another subsession left to
set up:</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT>
(g_setupSubsession->clientPortNum() == 0) </P>
<P><FONT color=#0000ff><FONT color=#0000ff>continue</FONT></FONT>; <FONT
color=#008000><FONT color=#008000>// port # was not set</P></FONT></FONT>
<P>SetupSubsession(g_setupSubsession, <FONT color=#0000ff><FONT
color=#0000ff>false</FONT></FONT>,
&CStreamReceiver::ContinueAfterSETUP);</P>
<P>g_madeSetupProgress = <FONT color=#0000ff><FONT
color=#0000ff>true</FONT></FONT>;</P>
<P><FONT color=#0000ff><FONT color=#0000ff>return</FONT></FONT>;</P>
<P>}</P>
<P><FONT color=#008000><FONT color=#008000>// We're done setting up
subsessions.</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>delete</FONT></FONT> setupIter;</P>
<P>setupIter = NULL;</P>
<P><FONT color=#008000><FONT color=#008000>//if
(!g_madeSetupProgress)</P></FONT></FONT>
<P><FONT color=#008000><FONT color=#008000>// Shutdown();</P></FONT></FONT>
<P>g_madeSetupProgress = <FONT color=#0000ff><FONT
color=#0000ff>false</FONT></FONT>;</P>
<P>MediaSubsessionIterator iter(*g_session);</P>
<P><FONT color=#0000ff><FONT color=#0000ff>while</FONT></FONT>
((g_setupSubsession = iter.next()) != NULL) </P>
<P>{</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT>
(g_setupSubsession->readSource() == NULL) </P>
<P><FONT color=#0000ff><FONT color=#0000ff>continue</FONT></FONT>; <FONT
color=#008000><FONT color=#008000>// was not initiated</P></FONT></FONT>
<P>PAYLOAD_FORMAT destFormat = PAYLOAD_NONE; <FONT color=#008000><FONT
color=#008000>//-1</P></FONT></FONT>
<P><FONT color=#008000><FONT color=#008000>//params.type - The type of input
device</P></FONT></FONT>
<P><FONT color=#008000><FONT color=#008000>//payloadType - the input
format</P></FONT></FONT>
<P><FONT color=#008000><FONT color=#008000>//params.format - the desired output
format</P></FONT></FONT>
<P><FONT color=#008000><FONT color=#008000>//Find a sink that converts from
payload type to output type (params). Use recursive function. Chain
together.</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_audioHandler
&& stricmp(g_setupSubsession->mediumName(), <FONT color=#a31515><FONT
color=#a31515>"audio"</FONT></FONT>) == 0)</P>
<P>{</P>
<P><FONT color=#008000><FONT color=#008000>//Need to figure out what the
required destination format is. PCM/RGB24/etc. (params.type)</P></FONT></FONT>
<P>map<string, string> params =
TokenizeParameters(g_audioHandler->GetOutputFormatParams());</P>
<P>map<string, string>::iterator itr;</P>
<P>itr = params.find(<FONT color=#a31515><FONT
color=#a31515>"DestinationFormatAudio"</FONT></FONT>);</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (itr !=
params.end())</P>
<P>destFormat = (PAYLOAD_FORMAT)(strtol((*itr).second.c_str(), NULL, 10));</P>
<P><FONT color=#008000><FONT color=#008000>//create a payload details struct
specifically for each sink, cannot use one global struct for two subsession
streams.</P></FONT></FONT>
<P>sPayloadInfo info;</P>
<P>info.payloadType = (PAYLOAD_FORMAT)g_setupSubsession->rtpPayloadFormat();
<FONT color=#008000><FONT color=#008000>//hopefully this populates with constant
invalid values (that can be checked against)</P></FONT></FONT>
<P>info.channels = g_setupSubsession->numChannels();</P>
<P>info.frequency = g_setupSubsession->rtpTimestampFrequency();</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (info.payloadType ==
PAYLOAD_PCMU || info.payloadType == PAYLOAD_PCMA)</P>
<P>info.bits = 16; <FONT color=#008000><FONT color=#008000>//hopefully this is
the correct value. (based on u-law documen tation)</P></FONT></FONT>
<P>g_audioMediaSink = g_setupSubsession->sink = <FONT color=#0000ff><FONT
color=#0000ff>static_cast</FONT></FONT><MediaSink
*>(CFFMPEGAudioMediaSink::createNew(*g_env, g_audioHandler, info,
destFormat));</P>
<P>}</P>
<P><FONT color=#0000ff><FONT color=#0000ff>else</FONT></FONT> <FONT
color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_videoHandler &&
stricmp(g_setupSubsession->mediumName(), <FONT color=#a31515><FONT
color=#a31515>"video"</FONT></FONT>) == 0) <FONT color=#008000><FONT
color=#008000>//make sure this subsession is a video stream</P></FONT></FONT>
<P>{</P>
<P><FONT color=#008000><FONT color=#008000>//Need to figure out what the
required destination format is. PCM/RGB24/etc. (params.type)</P></FONT></FONT>
<P>map<string, string> params =
TokenizeParameters(g_videoHandler->GetOutputFormatParams());</P>
<P>map<string, string>::iterator itr;</P>
<P>itr = params.find(<FONT color=#a31515><FONT
color=#a31515>"DestinationFormatVideo"</FONT></FONT>);</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (itr !=
params.end())</P>
<P>destFormat = (PAYLOAD_FORMAT)(strtol((*itr).second.c_str(), NULL, 10));</P>
<P>sPayloadInfo info;</P>
<P>info.payloadType = (PAYLOAD_FORMAT)g_setupSubsession->rtpPayloadFormat();
<FONT color=#008000><FONT color=#008000>//hopefully this populates with constant
invalid values (that can be checked against)</P></FONT></FONT>
<P>info.channels = g_setupSubsession->numChannels();</P>
<P>info.frequency = g_setupSubsession->rtpTimestampFrequency();</P>
<P><FONT color=#008000><FONT color=#008000>//I'm sure there must be a way to get
bpp, etc out of the subsession.</P></FONT></FONT>
<P>g_videoMediaSink = g_setupSubsession->sink = <FONT color=#0000ff><FONT
color=#0000ff>static_cast</FONT></FONT><MediaSink
*>(CFFMPEGVideoMediaSink::createNew(*g_env, g_videoHandler, info,
destFormat));</P>
<P>}</P>
<P><FONT color=#0000ff><FONT color=#0000ff>else</P></FONT></FONT>
<P>{</P>
<P>g_setupSubsession->sink = NULL;</P>
<P>LOG((*g_logger), <FONT color=#a31515><FONT color=#a31515>"Failed to create
sink for - "</FONT></FONT> << g_setupSubsession->mediumName());</P>
<P>}</P>
<P></P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT>
(g_setupSubsession->sink)</P>
<P>{</P>
<P>LOG((*g_logger), <FONT color=#a31515><FONT color=#a31515>"Playing sink -
"</FONT></FONT> << g_setupSubsession->mediumName());</P>
<P>g_setupSubsession->sink->startPlaying(*(g_setupSubsession->readSource()),
SubsessionAfterPlaying, g_setupSubsession);</P>
<P><FONT color=#008000><FONT color=#008000>// Also set a handler to be called if
a RTCP "BYE" arrives for this subsession:</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT>
(g_setupSubsession->rtcpInstance() != NULL) </P>
<P>g_setupSubsession->rtcpInstance()->setByeHandler(&CStreamReceiver::SubsessionByeHandler,
g_setupSubsession);</P>
<P>g_madeSetupProgress = <FONT color=#0000ff><FONT
color=#0000ff>true</FONT></FONT>;</P>
<P>}</P>
<P>}</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT>
(!g_madeSetupProgress) </P>
<P>Shutdown();</P>
<P><FONT color=#008000><FONT color=#008000>// Finally, start playing each
subsession, to start the data flow:</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_duration == 0)
</P>
<P>{</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_scale > 0)
</P>
<P>g_duration = g_session->playEndTime() - g_initialSeekTime; <FONT
color=#008000><FONT color=#008000>// use SDP end time</P></FONT></FONT>
<P><FONT color=#0000ff><FONT color=#0000ff>else</FONT></FONT> <FONT
color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_scale < 0) </P>
<P>g_duration = g_initialSeekTime;</P>
<P>}</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_duration < 0)
</P>
<P>g_duration = 0.0;</P>
<P>g_endTime = g_initialSeekTime;</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_scale > 0)
</P>
<P>{</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_duration <= 0)
</P>
<P>g_endTime = -1.0f;</P>
<P><FONT color=#0000ff><FONT color=#0000ff>else</FONT></FONT> </P>
<P>g_endTime = g_initialSeekTime + g_duration;</P>
<P>} </P>
<P><FONT color=#0000ff><FONT color=#0000ff>else</P></FONT></FONT>
<P>{</P>
<P>g_endTime = g_initialSeekTime - g_duration;</P>
<P><FONT color=#0000ff><FONT color=#0000ff>if</FONT></FONT> (g_endTime <
0)</P>
<P>g_endTime = 0.0f;</P>
<P>}</P>
<P>StartPlayingSession(g_session, g_initialSeekTime, g_endTime, g_scale,
&CStreamReceiver::ContinueAfterPLAY);</P></SPAN></DIV>
<DIV align=left><STRONG></STRONG> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>I can confirm that the
parameters are correct to each subsession and to each sink, which I have logs
for which indicate that everything succeeds, but the data simply does not
stream, possibly it's a deadlock, or a function I should be calling... I have
written a filter for the MPEG4 (using FFMPEG), and a simple audio filter to
conver the u-law/a-law data (camera supports both) to 16-bit signed linear pcm
data - which plays perfectly. I just need a tiny nudge in the right direction. I
have included my SDP response from the camera, just in case I have misread
something and the camera requires another step.</SPAN></STRONG></DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012></SPAN></STRONG> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>v=0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>o=RTSP 959993539 572 IN
IP4 0.0.0.0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>s=RTSP
server</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>c=IN IP4
0.0.0.0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>t=0
0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=charset:Shift_JIS</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=range:npt=0-</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=control:*</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=etag:1234567890</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>m=video 0 RTP/AVP
96</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>b=AS:0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>a=rtpmap:96
MP4V-ES/30000</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=control:trackID=1</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>a=fmtp:96
profile-level-id=3;config=000001B003000001B509000001010000012000845D4C28C82258A200;decode_buf=76800</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>m=audio 0 RTP/AVP
0</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>a=control:trackID=6</SPAN></STRONG></DIV>
<DIV> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>a=rtpmap:0
pcmu/8000</SPAN></STRONG></DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012></SPAN></STRONG> </DIV>
<DIV align=left><STRONG><SPAN class=867540013-14022012>Thank
you</SPAN></STRONG></DIV>
<DIV align=left><STRONG><SPAN
class=867540013-14022012>Regards</SPAN></STRONG></DIV>
<DIV align=left><STRONG>___________________________________</STRONG></DIV><BR>
<DIV align=left><STRONG>Shaheed Abdol</STRONG></DIV><BR>
<DIV align=left><FONT color=#909090 size=1><STRONG></STRONG></FONT></DIV><IMG
border=0 hspace=0 alt="Scansoft Technologies" align=baseline
src="cid:867540013@14022012-00B7"><BR>
<DIV align=left><FONT color=#909090 size=1><STRONG>Web: <A
href="http://www.scansoft.co.za/">www.scansoft.co.za</A></DIV>
<DIV align=left><FONT color=#909090 size=1><STRONG>Tel: +27 21 913
8664</STRONG></FONT></DIV>
<DIV align=left><FONT color=#909090 size=1><STRONG>Cell: +27 79 835
8771</STRONG></FONT></DIV></STRONG></FONT>
<DIV> </DIV></BODY></HTML>