player_session.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:16k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /* 
  22.  * player_session.cpp - describes player session class, which is the
  23.  * main access point for the player
  24.  */
  25. #include "systems.h"
  26. #include "player_session.h"
  27. #include "player_media.h"
  28. #include "player_sdp.h"
  29. #include "player_util.h"
  30. #include "audio.h"
  31. #include "video.h"
  32. #ifdef _WIN32
  33. DEFINE_MESSAGE_MACRO(sync_message, "avsync")
  34. #else
  35. #define sync_message(loglevel, fmt...) message(loglevel, "avsync", fmt)
  36. #endif
  37. /*
  38.  * c callback for sync thread
  39.  */
  40. CPlayerSession::CPlayerSession (CMsgQueue *master_mq, 
  41. SDL_sem *master_sem,
  42. const char *name)
  43. {
  44.   m_sdp_info = NULL;
  45.   m_my_media = NULL;
  46.   m_rtsp_client = NULL;
  47.   m_video_sync = NULL;
  48.   m_audio_sync = NULL;
  49.   m_sync_thread = NULL;
  50.   m_sync_sem = NULL;
  51.   m_content_base = NULL;
  52.   m_master_msg_queue = master_mq;
  53.   m_master_msg_queue_sem = master_sem;
  54.   m_paused = 0;
  55.   m_streaming = 0;
  56.   m_session_name = strdup(name);
  57.   m_audio_volume = 75;
  58.   m_current_time = 0;
  59.   m_seekable = 0;
  60.   m_session_state = SESSION_PAUSED;
  61.   m_screen_pos_x = 0;
  62.   m_screen_pos_y = 0;
  63.   m_clock_wrapped = -1;
  64.   m_hardware_error = 0;
  65.   m_fullscreen = 0;
  66.   m_session_control_is_aggregate = 0;
  67.   for (int ix = 0; ix < SESSION_DESC_COUNT; ix++) {
  68.     m_session_desc[ix] = NULL;
  69.   }
  70.   m_media_close_callback = NULL;
  71.   m_media_close_callback_data = NULL;
  72.   m_streaming_media_set_up = 0;
  73.   m_unused_ports = NULL;
  74.   m_first_time_played = 0;
  75.   m_latency = 0;
  76. }
  77. CPlayerSession::~CPlayerSession ()
  78. {
  79.   int hadthread = 0;
  80. #ifndef _WINDOWS
  81.   if (m_sync_thread) {
  82.     send_sync_thread_a_message(MSG_STOP_THREAD);
  83.     SDL_WaitThread(m_sync_thread, NULL);
  84.     m_sync_thread = NULL;
  85.     hadthread = 1;
  86.   }
  87. #else
  88.   send_sync_thread_a_message(MSG_STOP_THREAD);
  89.   hadthread = 1;
  90. #endif
  91.   if (m_streaming_media_set_up != 0 &&
  92.       session_control_is_aggregate()) {
  93.     rtsp_command_t cmd;
  94.     rtsp_decode_t *decode;
  95.     memset(&cmd, 0, sizeof(rtsp_command_t));
  96.     rtsp_send_aggregate_teardown(m_rtsp_client,
  97.  m_sdp_info->control_string,
  98.  &cmd,
  99.  &decode);
  100.     free_decode_response(decode);
  101.   }
  102.   if (m_rtsp_client) {
  103.     free_rtsp_client(m_rtsp_client);
  104.     m_rtsp_client = NULL;
  105.   }
  106.   while (m_my_media != NULL) {
  107.     CPlayerMedia *p;
  108.     p = m_my_media;
  109.     m_my_media = p->get_next();
  110.     delete p;
  111.   }  
  112.   if (m_sdp_info) {
  113.     sdp_free_session_desc(m_sdp_info);
  114.     m_sdp_info = NULL;
  115.   }
  116.   if (m_sync_sem) {
  117.     SDL_DestroySemaphore(m_sync_sem);
  118.     m_sync_sem = NULL;
  119.   }
  120.   
  121.   if (m_video_sync != NULL) {
  122.     delete m_video_sync;
  123.     m_video_sync = NULL;
  124.   }
  125.   if (m_audio_sync != NULL) {
  126.     delete m_audio_sync;
  127.     m_audio_sync = NULL;
  128.   }
  129.   if (m_session_name) {
  130.     free((void *)m_session_name);
  131.     m_session_name = NULL;
  132.   }
  133.   if (m_content_base) {
  134.     free((void *) m_content_base);
  135.     m_content_base = NULL;
  136.   }
  137.   for (int ix = 0; ix < SESSION_DESC_COUNT; ix++) {
  138.     if (m_session_desc[ix] != NULL) 
  139.       free((void *)m_session_desc[ix]);
  140.     m_session_desc[ix] = NULL;
  141.   }
  142.   
  143.   if (m_media_close_callback != NULL) {
  144.     m_media_close_callback(m_media_close_callback_data);
  145.   }
  146.   while (m_unused_ports != NULL) {
  147.     CIpPort *first;
  148.     first = m_unused_ports;
  149.     m_unused_ports = first->get_next();
  150.     delete first;
  151.   }
  152.   if (hadthread != 0) {
  153.     SDL_Quit();
  154.   }
  155. }
  156. int CPlayerSession::create_streaming_broadcast (session_desc_t *sdp,
  157. char *ermsg,
  158. uint32_t errlen)
  159. {
  160.   session_set_seekable(0);
  161.   m_sdp_info = sdp;
  162.   m_streaming = 1;
  163.   m_rtp_over_rtsp = 0;
  164.   return (0);
  165. }
  166. /*
  167.  * create_streaming - create a session for streaming.  Create an
  168.  * RTSP session with the server, get the SDP information from it.
  169.  */
  170. int CPlayerSession::create_streaming_ondemand (const char *url, 
  171.        char *errmsg,
  172.        uint32_t errlen, 
  173.        int use_tcp)
  174. {
  175.   rtsp_command_t cmd;
  176.   rtsp_decode_t *decode;
  177.   sdp_decode_info_t *sdpdecode;
  178.   int dummy;
  179.   int err;
  180.   // streaming has seek capability (at least on demand)
  181.   session_set_seekable(1);
  182.   player_debug_message("Creating streaming %s", url);
  183.   memset(&cmd, 0, sizeof(rtsp_command_t));
  184.   /*
  185.    * create RTSP session
  186.    */
  187.   if (use_tcp != 0) {
  188.     m_rtsp_client = rtsp_create_client_for_rtp_tcp(url, &err);
  189.   } else {
  190.     m_rtsp_client = rtsp_create_client(url, &err);
  191.   }
  192.   if (m_rtsp_client == NULL) {
  193.     snprintf(errmsg, errlen, "Failed to create RTSP client");
  194.     player_error_message("Failed to create rtsp client - error %d", err);
  195.     return (err);
  196.   }
  197.   m_rtp_over_rtsp = use_tcp;
  198.   cmd.accept = "application/sdp";
  199.   /*
  200.    * Send the RTSP describe.  This should return SDP information about
  201.    * the session.
  202.    */
  203.   if (rtsp_send_describe(m_rtsp_client, &cmd, &decode) !=
  204.       RTSP_RESPONSE_GOOD) {
  205.     int retval;
  206.     if (decode != NULL) {
  207.       retval = (((decode->retcode[0] - '0') * 100) +
  208. ((decode->retcode[1] - '0') * 10) +
  209. (decode->retcode[2] - '0'));
  210.     } else {
  211.       retval = -1;
  212.     }
  213.     snprintf(errmsg, errlen, "RTSP describe error %d %s", retval,
  214.      decode->retresp != NULL ? decode->retresp : "");
  215.     player_error_message("Describe response not goodn");
  216.     free_decode_response(decode);
  217.     return (retval);
  218.   }
  219.   sdpdecode = set_sdp_decode_from_memory(decode->body);
  220.   if (sdpdecode == NULL) {
  221.     snprintf(errmsg, errlen, "Memory failure");
  222.     player_error_message("Couldn't get sdp decoden");
  223.     free_decode_response(decode);
  224.     return (-1);
  225.   }
  226.   /*
  227.    * Decode the SDP information into structures we can use.
  228.    */
  229.   err = sdp_decode(sdpdecode, &m_sdp_info, &dummy);
  230.   free(sdpdecode);
  231.   if (err != 0) {
  232.     snprintf(errmsg, errlen, "Couldn't decode session description %s",
  233.      decode->body);
  234.     player_error_message("Couldn't decode sdp %s", decode->body);
  235.     free_decode_response(decode);
  236.     return (-1);
  237.   }
  238.   if (dummy != 1) {
  239.     snprintf(errmsg, errlen, "Incorrect number of sessions in sdp decode %d",
  240.      dummy);
  241.     player_error_message(errmsg);
  242.     free_decode_response(decode);
  243.     return (-1);
  244.   }
  245.   if (m_sdp_info->control_string != NULL) {
  246.     set_session_control(1);
  247.   }
  248.   /*
  249.    * Make sure we can use the urls in the sdp info
  250.    */
  251.   if (decode->content_location != NULL) {
  252.     // Note - we may have problems if the content location is not absolute.
  253.     m_content_base = strdup(decode->content_location);
  254.   } else if (decode->content_base != NULL) {
  255.     m_content_base = strdup(decode->content_base);
  256.   } else {
  257.     int urllen = strlen(url);
  258.     if (url[urllen] != '/') {
  259.       char *temp;
  260.       temp = (char *)malloc(urllen + 2);
  261.       strcpy(temp, url);
  262.       strcat(temp, "/");
  263.       m_content_base = temp;
  264.     } else {
  265.       m_content_base = strdup(url);
  266.     }
  267.   }
  268.   convert_relative_urls_to_absolute(m_sdp_info,
  269.     m_content_base);
  270.   free_decode_response(decode);
  271.   m_streaming = 1;
  272.   return (0);
  273. }
  274. CVideoSync * CPlayerSession::set_up_video_sync (void)
  275. {
  276.   if (m_video_sync == NULL) {
  277.     m_video_sync = create_video_sync(this);
  278.   }
  279.   return m_video_sync;
  280. }
  281. CAudioSync *CPlayerSession::set_up_audio_sync (void)
  282. {
  283.   if (m_audio_sync == NULL) {
  284.     m_audio_sync = create_audio_sync(this, m_audio_volume);
  285.   }
  286.   return m_audio_sync;
  287. }
  288. /*
  289.  * set_up_sync_thread.  Creates the sync thread, and a sync class
  290.  * for each media
  291.  */
  292. void CPlayerSession::set_up_sync_thread(void) 
  293. {
  294.   CPlayerMedia *media;
  295.   media = m_my_media;
  296.   while (media != NULL) {
  297.     if (media->is_video()) {
  298.       media->set_video_sync(set_up_video_sync());
  299.     } else {
  300.        media->set_audio_sync(set_up_audio_sync());
  301.     }
  302.     media= media->get_next();
  303.   }
  304.   m_sync_sem = SDL_CreateSemaphore(0);
  305. #ifndef _WINDOWS
  306.   m_sync_thread = SDL_CreateThread(c_sync_thread, this);
  307. #endif
  308. }
  309. /*
  310.  * play_all_media - get all media to play
  311.  */
  312. int CPlayerSession::play_all_media (int start_from_begin, double start_time)
  313. {
  314.   int ret;
  315.   CPlayerMedia *p;
  316.   range_desc_t *range;
  317.   if (m_sdp_info && m_sdp_info->session_range.have_range != FALSE) {
  318.     range = &m_sdp_info->session_range;
  319.   } else {
  320.     range = NULL;
  321.     p = m_my_media;
  322.     while (range == NULL && p != NULL) {
  323.       media_desc_t *media;
  324.       media = p->get_sdp_media_desc();
  325.       if (media && media->media_range.have_range) {
  326. range = &media->media_range;
  327.       }
  328.       p = p->get_next();
  329.     }
  330.   }
  331.   p = m_my_media;
  332.   m_session_state = SESSION_BUFFERING;
  333.   if (m_paused == 1 && start_time == 0.0 && start_from_begin == FALSE) {
  334.     /*
  335.      * we were paused.  Continue.
  336.      */
  337.     m_play_start_time = m_current_time;
  338. #ifdef _WINDOWS
  339. start_time = (double)(int64_t)m_current_time;
  340. #else
  341.     start_time = (double) m_current_time;
  342. #endif
  343.     start_time /= 1000.0;
  344.     player_debug_message("Restarting at " LLU ", %g", m_current_time, start_time);
  345.   } else {
  346.     /*
  347.      * We might have been paused, but we're told to seek
  348.      */
  349.     // Indicate what time we're starting at for sync task.
  350.     m_play_start_time = (uint64_t)(start_time * 1000.0);
  351.   }
  352.   m_paused = 0;
  353.   send_sync_thread_a_message(MSG_START_SESSION);
  354.   // If we're doing aggregate rtsp, send the play command...
  355.   if (session_control_is_aggregate()) {
  356.     char buffer[80];
  357.     rtsp_command_t cmd;
  358.     rtsp_decode_t *decode;
  359.     memset(&cmd, 0, sizeof(rtsp_command_t));
  360.     if (range != NULL) {
  361.       sprintf(buffer, "npt=%g-%g", start_time, range->range_end);
  362.       cmd.range = buffer;
  363.     }
  364.     if (rtsp_send_aggregate_play(m_rtsp_client,
  365.  m_sdp_info->control_string,
  366.  &cmd,
  367.  &decode) != 0) {
  368.       player_debug_message("RTSP aggregate play command failed");
  369.       free_decode_response(decode);
  370.       return (-1);
  371.     }
  372.     if (decode->rtp_info == NULL) {
  373.       player_error_message("No rtp info field");
  374.     } else {
  375.       player_debug_message("rtp info is '%s'", decode->rtp_info);
  376.     }
  377.     int ret = process_rtsp_rtpinfo(decode->rtp_info, this, NULL);
  378.     free_decode_response(decode);
  379.     if (ret < 0) {
  380.       player_debug_message("rtsp aggregate rtpinfo failed");
  381.       return (-1);
  382.     }
  383.   }
  384.   while (p != NULL) {
  385.     ret = p->do_play(start_time);
  386.     if (ret != 0) return (ret);
  387.     p = p->get_next();
  388.   }
  389.   return (0);
  390. }
  391. /*
  392.  * pause_all_media - do a spin loop until the sync thread indicates it's
  393.  * paused.
  394.  */
  395. int CPlayerSession::pause_all_media (void) 
  396. {
  397.   int ret;
  398.   CPlayerMedia *p;
  399.   m_session_state = SESSION_PAUSED;
  400.   if (session_control_is_aggregate()) {
  401.     rtsp_command_t cmd;
  402.     rtsp_decode_t *decode;
  403.     memset(&cmd, 0, sizeof(rtsp_command_t));
  404.     if (rtsp_send_aggregate_pause(m_rtsp_client,
  405.   m_sdp_info->control_string,
  406.   &cmd,
  407.   &decode) != 0) {
  408.       player_debug_message("RTSP aggregate pause command failed");
  409.       free_decode_response(decode);
  410.       return (-1);
  411.     }
  412.     free_decode_response(decode);
  413.   }
  414.   p = m_my_media;
  415.   while (p != NULL) {
  416.     ret = p->do_pause();
  417.     if (ret != 0) return (ret);
  418.     p = p->get_next();
  419.   }
  420.   m_sync_pause_done = 0;
  421.   send_sync_thread_a_message(MSG_PAUSE_SESSION);
  422. #ifndef _WINDOWS
  423.   do {
  424. #endif
  425.     SDL_Delay(100);
  426. #ifndef _WINDOWS
  427.   } while (m_sync_pause_done == 0);
  428. #endif
  429.   m_paused = 1;
  430.   return (0);
  431. }
  432. void CPlayerSession::add_media (CPlayerMedia *m) 
  433. {
  434.   CPlayerMedia *p;
  435.   if (m_my_media == NULL) {
  436.     m_my_media = m;
  437.   } else {
  438.     p = m_my_media;
  439.     while (p->get_next() != NULL) {
  440.       if (p == m) return;
  441.       p = p->get_next();
  442.     }
  443.     p->set_next(m);
  444.   }
  445. }
  446. int CPlayerSession::session_has_audio (void)
  447. {
  448.   CPlayerMedia *p;
  449.   p = m_my_media;
  450.   while (p != NULL) {
  451.     if (p->is_video() == FALSE) {
  452.       return (1);
  453.     }
  454.     p = p->get_next();
  455.   }
  456.   return (0);
  457. }
  458. int CPlayerSession::session_has_video (void)
  459. {
  460.   CPlayerMedia *p;
  461.   p = m_my_media;
  462.   while (p != NULL) {
  463.     if (p->is_video() != FALSE) {
  464.       return (1);
  465.     }
  466.     p = p->get_next();
  467.   }
  468.   return (0);
  469. }
  470. void CPlayerSession::set_audio_volume (int volume)
  471. {
  472.   m_audio_volume = volume;
  473.   if (m_audio_sync) {
  474.     m_audio_sync->set_volume(m_audio_volume);
  475.   }
  476. }
  477. void CPlayerSession::set_screen_location (int x, int y)
  478. {
  479.   m_screen_pos_x = x;
  480.   m_screen_pos_y = y;
  481. }
  482. void CPlayerSession::set_screen_size (int scaletimes2, int fullscreen)
  483. {
  484.   m_screen_scale = scaletimes2;
  485.   m_fullscreen = fullscreen;
  486.   if (m_video_sync) {
  487.     m_video_sync->set_screen_size(scaletimes2);
  488.     m_video_sync->set_fullscreen(fullscreen);
  489.     send_sync_thread_a_message(MSG_SYNC_RESIZE_SCREEN);
  490.   }
  491. }
  492. double CPlayerSession::get_max_time (void)
  493. {
  494.   CPlayerMedia *p;
  495.   double max = 0.0;
  496.   p = m_my_media;
  497.   while (p != NULL) {
  498.     double temp = p->get_max_playtime();
  499.     if (temp > max) max = temp;
  500.     p = p->get_next();
  501.   }
  502.   return (max);
  503. }
  504. /*
  505.  * Matches a url with the corresponding media. 
  506.  * Return the media, or NULL if no match. 
  507.  */
  508. CPlayerMedia *CPlayerSession::rtsp_url_to_media (const char *url)
  509. {
  510.   CPlayerMedia *p = m_my_media;
  511.   while (p != NULL) {
  512. rtsp_session_t *session = p->get_rtsp_session();
  513. if (rtsp_is_url_my_stream(session, url, m_content_base, 
  514.   m_session_name) == 1) 
  515.   return p;
  516.     p = p->get_next();
  517.   }
  518.   return (NULL);
  519. }
  520. int CPlayerSession::set_session_desc (int line, const char *desc)
  521. {
  522.   if (line >= SESSION_DESC_COUNT) {
  523.     return -1;
  524.   }
  525.   if (m_session_desc[line] != NULL) free((void *)m_session_desc[line]);
  526.   m_session_desc[line] = strdup(desc);
  527.   if (m_session_desc[line] == NULL) 
  528.     return -1;
  529.   return (0);
  530. }
  531. const char *CPlayerSession::get_session_desc (int line)
  532. {
  533.   return m_session_desc[line];
  534. }
  535. /*
  536.  * audio_is_ready - when the audio indicates that it's ready, it will
  537.  * send a latency number, and a play time
  538.  */
  539. void CPlayerSession::audio_is_ready (uint64_t latency, uint64_t time)
  540. {
  541.   m_start = get_time_of_day();
  542.   sync_message(LOG_DEBUG, "Aisready "LLU, m_start);
  543.   m_start -= time;
  544.   m_latency = latency;
  545.   if (latency != 0) {
  546.     m_clock_wrapped = -1;
  547.   }
  548.   sync_message(LOG_DEBUG, "Audio is ready "LLU" - latency "LLU, time, latency);
  549.   sync_message(LOG_DEBUG, "m_start is "LLX, m_start);
  550.   m_waiting_for_audio = 0;
  551.   SDL_SemPost(m_sync_sem);
  552. }
  553. void CPlayerSession::adjust_start_time (int64_t time)
  554. {
  555.   m_start -= time;
  556.   m_clock_wrapped = -1;
  557. #if 0
  558.   sync_message(LOG_INFO, "Adjusting start time "LLD " to " LLU, time,
  559.        get_current_time());
  560. #endif
  561.   SDL_SemPost(m_sync_sem);
  562. }
  563. /*
  564.  * get_current_time.  Gets the time of day, subtracts off the start time
  565.  * to get the current play time.
  566.  */
  567. uint64_t CPlayerSession::get_current_time (void)
  568. {
  569.   uint64_t current_time;
  570.   if (m_waiting_for_audio != 0) {
  571.     return 0;
  572.   }
  573.   current_time = get_time_of_day();
  574. #if 0
  575.   sync_message(LOG_DEBUG, "current time %llx m_start %llx", 
  576.        current_time, m_start);
  577.   if (current_time < m_start) {
  578.     if (m_clock_wrapped == -1) {
  579.       return (0);
  580.     } else {
  581.       m_clock_wrapped = 1;
  582.     }
  583.   } else{
  584.     if (m_clock_wrapped > 0) {
  585.       uint64_t temp;
  586.       temp = 1;
  587.       temp <<= 32;
  588.       temp /= 1000;
  589.       current_time += temp;
  590.     } else {
  591.       m_clock_wrapped = 0;
  592.     }
  593.   }
  594. #endif
  595.   //if (current_time < m_start) return 0;
  596.   m_current_time = current_time - m_start;
  597.   if (m_current_time >= m_latency) m_current_time -= m_latency;
  598.   return(m_current_time);
  599. }
  600. /* end file player_session.cpp */