<!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>