freeswitch系列7 IO

freeswitch的大部分媒體邏輯在switch_ivr_*.c中實現,但是這些是功能邏輯,最後會調用switch_core_io.c中的讀寫幀函數進行io操作。本章不分析功能,只對讀寫幀這些底層IO的API進行分析。

 

 

 

  1. switch_core_session_read_frame

讀寫幀代碼比較長,這裏對關鍵流程進行註解。

對一些參數進行判斷

  1. if (!switch_core_codec_ready(session->read_codec)) {  

 

從端點讀幀

 

  1. if (session->endpoint_interface->io_routines->read_frame) {  
  2.     switch_mutex_unlock(session->read_codec->mutex);  
  3.     switch_mutex_unlock(session->codec_read_mutex);  
  4.     if ((status = session->endpoint_interface->io_routines->read_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {  
  5.         for (ptr = session->event_hooks.read_frame; ptr; ptr = ptr->next) {  
  6.             if ((status = ptr->read_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {  
  7.                 break;  
  8.             }  
  9.         }  
  10.     }  

 

調用端點的io接口去讀,io層不具體去讀,而是調用端點的接口,說明它支持很多種讀法,如果是mod_sofia,從網絡讀RTP,在mod_portaudio則從本地聲卡讀。另外,除了端點可以讀,還可以從事件回調接口讀,session->event_hooks.read_frame。

傳給監控媒體流

 

  1. if (bp->ready) {  
  2.     if (switch_test_flag(bp, SMBF_TAP_NATIVE_READ)) {  
  3.         if ((*frame)->codec && (*frame)->codec->implementation &&   
  4.             (*frame)->codec->implementation->encoded_bytes_per_packet &&   
  5.             (*frame)->datalen != (*frame)->codec->implementation->encoded_bytes_per_packet) {  
  6.             switch_set_flag((*frame), SFF_CNG);  
  7.             break;  
  8.         }  
  9.         if (bp->callback) {  
  10.             bp->native_read_frame = *frame;  
  11.             ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_TAP_NATIVE_READ);  
  12.             bp->native_read_frame = NULL;  
  13.         }  
  14.     }  
  15. }  

 

freeswitch支持通過bug這種機制進行監控媒體流,這裏會把讀到的幀傳給監控bug。

 

解碼幀

  1. status = switch_core_codec_decode(codec,  
  2.                                   session->read_codec,  
  3.                                   read_frame->data,  
  4.                                   read_frame->datalen,  
  5.                                   session->read_impl.actual_samples_per_second,  
  6.                                   session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate,   
  7.                                   &read_frame->flags);  
  8.           

 

從網絡讀到的RTP包是編碼的,這裏如果code不一樣,或者直接播放,要進行解碼。

重採樣

 

  1. case SWITCH_STATUS_RESAMPLE:  
  2.     if (!session->read_resampler) {  
  3.         switch_mutex_lock(session->resample_mutex);  
  4.   
  5.         status = switch_resample_create(&session->read_resampler,  
  6.                                         read_frame->codec->implementation->actual_samples_per_second,  
  7.                                         session->read_impl.actual_samples_per_second,  
  8.                                         session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY,   
  9.                                         session->read_impl.number_of_channels); 

 

除了支持轉碼,還支持重採樣。

 

再編碼

  1. status = switch_core_codec_encode(session->read_codec,  
  2.                                   enc_frame->codec,  
  3.                                   enc_frame->data,  
  4.                                   enc_frame->datalen,  
  5.                                   session->read_impl.actual_samples_per_second,  
  6.                                   session->enc_read_frame.data, &session->enc_read_frame.datalen, &session->enc_read_frame.rate, &flag);  

所謂轉碼,就是兩端協商使用的codec不一樣,A的媒體數據,freeswitch先解碼成中間格式L16,再編碼成B支持的codec。

  1. switch_core_session_write_frame

 

快速發

  1. if (switch_test_flag(frame, SFF_PROXY_PACKET) || pass_cng) {  
  2.     /* Fast PASS! */  
  3.     switch_mutex_lock(session->codec_write_mutex);  
  4.     status = perform_write(session, frame, flag, stream_id);  
  5.     switch_mutex_unlock(session->codec_write_mutex);  
  6.     return status;  
  7. }  

有些情況,比如這個是代理包標誌還是啥,就要調用perform_write直接發。

 

轉碼

  1. if (frame->codec) {  
  2.     session->raw_write_frame.datalen = session->raw_write_frame.buflen;  
  3.     frame->codec->cur_frame = frame;  
  4.     session->write_codec->cur_frame = frame;  
  5.     status = switch_core_codec_decode(frame->codec,  
  6.                                       session->write_codec,  
  7.                                       frame->data,  
  8.                                       frame->datalen,  
  9.                                       session->write_impl.actual_samples_per_second,  
  10.                                       session->raw_write_frame.data, &session->raw_write_frame.datalen, &session->raw_write_frame.rate, &frame->flags); 

 

重採樣

  1. switch (status) {  
  2. case SWITCH_STATUS_RESAMPLE:  
  3.     resample++;  
  4.     write_frame = &session->raw_write_frame;  
  5.     write_frame->rate = frame->codec->implementation->actual_samples_per_second;  
  6.     if (!session->write_resampler) {  
  7.         switch_mutex_lock(session->resample_mutex);  
  8.         status = switch_resample_create(&session->write_resampler,  
  9.                                         frame->codec->implementation->actual_samples_per_second,  
  10.                                         session->write_impl.actual_samples_per_second,  
  11.                                         session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, session->write_impl.number_of_channels);  
  12.  
  13. switch_resample_process(session->write_resampler, data, write_frame->datalen / 2 / session->write_resampler->channels);

 

再編碼

  1. status = switch_core_codec_encode(session->write_codec,  
  2.                                   frame->codec,  
  3.                                   enc_frame->data,  
  4.                                   enc_frame->datalen,  
  5.                                   session->write_impl.actual_samples_per_second,  
  6.                                   session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag);  

 

都處理完後,最後調用perform_write把數據發出去。

 

  1.  done:  
  2.   
  3. if (ptime_mismatch || resample) {  
  4.     write_frame->timestamp = 0;  
  5. }  
  6.   
  7. if (do_write) {  
  8.     status = perform_write(session, write_frame, flags, stream_id);  
  9. }  

 

perform_write實際調用端點的IO函數。

 

  1.     if (session->endpoint_interface->io_routines->write_frame) {  
  2.         if ((status = session->endpoint_interface->io_routines->write_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {  
  3.             for (ptr = session->event_hooks.write_frame; ptr; ptr = ptr->next) {  
  4.                 if ((status = ptr->write_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {  
  5.                     break;  
  6.                 }  
  7.             }  
  8.         }  
  9.     }  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章