// Calculate the number of samples per packet size_t MastCodec_MPA::frames_per_packet_internal( size_t max_bytes ) { int frames_per_packet = max_bytes/twolame_get_framelength( this->twolame ); MAST_DEBUG("MPEG Audio Frames per Packet: %d", frames_per_packet ); return frames_per_packet*TWOLAME_SAMPLES_PER_FRAME; }
/* mast_fill_input_buffer() Make sure input buffer if full of audio */ size_t mast_fill_input_buffer( MastAudioBuffer* buffer ) { size_t total_read = 0; int frames_wanted = buffer->get_write_space(); int frames_read = 0; if (frames_wanted==0) { // No audio wanted MAST_DEBUG( "Tried to fill buffer when it is full" ); return 0; } // Loop until buffer is full while( frames_wanted > 0 ) { frames_wanted = buffer->get_write_space(); frames_read = sf_readf_float( g_input_file, buffer->get_write_ptr(), frames_wanted ); // Add on the frames read if (frames_read > 0) { buffer->add_frames( frames_read ); total_read += frames_read; } // Reached end of file? if (frames_read < frames_wanted) { MAST_DEBUG("Reached end of file (frames_wanted=%d, frames_read=%d)", frames_wanted, frames_read); if (g_loop_file) { // Seek back to the beginning if (sf_seek( g_input_file, 0, SEEK_SET )) { MAST_ERROR("Failed to seek to start of file: %s", sf_strerror( g_input_file ) ); return 0; } } else { // Reached end of file (and don't want to loop) break; } } } if (total_read == 0) { MAST_ERROR("Failed to read from file: %s", sf_strerror( g_input_file ) ); } return total_read; }
// Constructors MastTool::MastTool( const char* tool_name, RtpSessionMode mode ) { int log_level = ORTP_WARNING|ORTP_ERROR|ORTP_FATAL; // Initialise defaults this->session = NULL; this->profile = &av_profile; this->mimetype = new MastMimeType(); this->payloadtype = NULL; this->payloadtype_index = -1; this->tool_name = tool_name; this->payload_size_limit = DEFAULT_PAYLOAD_LIMIT; // Initialise the oRTP library ortp_init(); // Set the logging message level #ifdef DEBUGGING MAST_DEBUG( "Compiled with debugging enabled" ); log_level |= ORTP_DEBUG; log_level |= ORTP_MESSAGE; #endif ortp_set_log_level_mask(log_level); // Create RTP session session = rtp_session_new( mode ); if (session==NULL) { MAST_FATAL( "Failed to create oRTP session.\n" ); } // Enabled multicast loopback rtp_session_set_multicast_loopback(session, TRUE); // Callbacks rtp_session_signal_connect(session,"ssrc_changed",(RtpCallback)ssrc_changed_cb, 0); rtp_session_signal_connect(session,"payload_type_changed",(RtpCallback)pt_changed_cb, 0); rtp_session_signal_connect(session,"network_error",(RtpCallback)network_error_cb, 0); // Set the MPEG Audio payload type to 14 in the AV profile rtp_profile_set_payload(profile, RTP_MPEG_AUDIO_PT, &payload_type_mpeg_audio); // Set RTCP parameters this->set_source_sdes(); }
// Callback called by JACK when buffersize changes static int buffersize_callback(jack_nframes_t nframes, void *arg) { MastSendTool* tool = (MastSendTool*)arg; int channels = tool->get_input_channels(); MAST_DEBUG("JACK buffer size is %d samples long", nframes); // (re-)allocate conversion buffer g_interleavebuf = (jack_default_audio_sample_t*) realloc( g_interleavebuf, nframes * sizeof(float) * channels ); if (g_interleavebuf == NULL) { MAST_FATAL("Failed to (re-)allocate the convertion buffer"); } // Success return 0; }
int MastCodec_MPA::set_param_internal( const char* name, const char* value ) { /* Parameters listed in RFC3555 for audio/MPA: layer: 1,2,3 samplerate: mode: "stereo", "joint_stereo", "single_channel", "dual_channel" bitrate: the data rate for the audio bit stream ptime: duration of each packet in milliseconds maxptime: maximum duration of each packet in milliseconds Example: audio/MPA;layer=2;mode=stereo;bitrate=160; */ if (strcmp(name, "layer")==0) { int layer = atoi(value); if (layer!=2) return -2; } else if (strcmp(name, "mode")==0) { TWOLAME_MPEG_mode mode; if (strcmp(value, "stereo")==0) mode = TWOLAME_STEREO; else if (strcmp(value, "joint_stereo")==0) mode = TWOLAME_JOINT_STEREO; else if (strcmp(value, "single_channel")==0) mode = TWOLAME_MONO; else if (strcmp(value, "dual_channel")==0) mode = TWOLAME_DUAL_CHANNEL; else return -2; if (twolame_set_mode( this->twolame, mode )) { MAST_WARNING("Failed to set mode"); } } else if (strcmp(name, "bitrate")==0) { int bitrate = atoi(value); if (twolame_set_bitrate( this->twolame, bitrate )) { MAST_WARNING("Failed to set bitrate"); } else { MAST_DEBUG("Set bitrate to %d", bitrate); } } else { // Unsupported parameter return -1; } // Success return 0; }
/* Take an hex SSRC string (from command line) and set it for session */ void MastTool::set_session_ssrc( const char* ssrc_str ) { int ssrc = 0; // Remove 0x from the start of the string if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) { ssrc_str += 2; } // Parse the hexadecimal number into an integer if (sscanf(ssrc_str, "%x", &ssrc)<=0) { MAST_ERROR("SSRC should be a hexadeicmal number"); return; } // Set it in the session MAST_DEBUG( "SSRC for session set to 0x%x", ssrc ); rtp_session_set_ssrc( session, ssrc ); }
int main(int argc, char **argv) { MastTool* tool = NULL; RtpProfile* profile = &av_profile; PayloadType* pt = NULL; FILE* output = NULL; mblk_t* packet = NULL; int ts_diff = 0; int ts = 0; // Create an RTP session tool = new MastTool( MAST_TOOL_NAME, RTP_SESSION_RECVONLY ); tool->enable_scheduling(); // Parse the command line arguments // and configure the session parse_cmd_line( argc, argv, tool ); // Recieve an initial packet packet = tool->wait_for_rtp_packet(); if (packet == NULL) MAST_FATAL("Failed to receive an initial packet"); // Lookup the payload type pt = rtp_profile_get_payload( profile, rtp_get_payload_type( packet ) ); if (pt == NULL) MAST_FATAL( "Payload type %d isn't registered with oRTP", rtp_get_payload_type( packet ) ); fprintf(stderr, "Payload type: %s\n", payload_type_get_rtpmap( pt )); // Work out the duration of the packet ts_diff = mast_rtp_packet_duration( packet ); MAST_DEBUG("ts_diff = %d", ts_diff); // Open the output file output = open_output_file( g_filename ); if (output==NULL) MAST_FATAL( "failed to open output file" ); // We can free the packet now freemsg( packet ); // Setup signal handlers mast_setup_signals(); // The main loop while( mast_still_running() ) { // Read in a packet packet = rtp_session_recvm_with_ts( tool->get_session(), ts ); if (packet==NULL) { MAST_DEBUG( "packet is NULL" ); } else { int data_len = mast_rtp_packet_size( packet ); if (data_len==0) { MAST_WARNING("Failed to get size of packet's payload"); } else { unsigned char* data_ptr = packet->b_cont->b_rptr; int bytes_written = 0; // Skip the extra header for MPA payload if (rtp_get_payload_type( packet ) == RTP_MPEG_AUDIO_PT) { data_ptr += 4; data_len -= 4; } // Update the timestamp difference ts_diff = mast_rtp_packet_duration( packet ); MAST_DEBUG("ts_diff = %d", ts_diff); MAST_DEBUG("data_len = %d", data_len); // Write to disk bytes_written = fwrite( data_ptr, 1, data_len, output ); if (bytes_written != data_len) { MAST_ERROR("Failed to write data to disk: %s", strerror(errno) ); break; } } } // Increment the timestamp for the next packet ts += ts_diff; } // Close output file if (fclose( output )) { MAST_ERROR("Failed to close output file:\n%s", strerror(errno)); } // Close RTP session delete tool; // Success return 0; }