/* mast_fill_input_buffer() Make sure input buffer if full of audio */ size_t mast_fill_input_buffer( MastAudioBuffer* buffer ) { int frames_wanted = buffer->get_write_space(); size_t bytes_wanted = frames_wanted * buffer->get_channels() * sizeof( mast_sample_t ); size_t bytes_read = 0, frames_read = 0; // Keep checking that there is enough audio available while (jack_ringbuffer_read_space(g_ringbuffer) < bytes_wanted) { MAST_WARNING( "Not enough audio available in ringbuffer; waiting" ); //MAST_DEBUG("Ring buffer is %u%% full", (jack_ringbuffer_read_space(g_ringbuffer)*100) / g_ringbuffer->size); // Wait for some more audio to become available pthread_mutex_lock(&g_ringbuffer_cond_mutex); pthread_cond_wait(&g_ringbuffer_cond, &g_ringbuffer_cond_mutex); pthread_mutex_unlock(&g_ringbuffer_cond_mutex); } // Copy frames from ring buffer to temporary buffer bytes_read = jack_ringbuffer_read(g_ringbuffer, (char*)buffer->get_write_ptr(), bytes_wanted); if (bytes_read<=0) MAST_FATAL( "Failed to read from ringbuffer" ); if (bytes_read!=bytes_wanted) MAST_WARNING("Failed to read enough audio for a full packet"); // Mark the space in the buffer as used frames_read = bytes_read / (buffer->get_channels() * sizeof( mast_sample_t )); buffer->add_frames( frames_read ); // Return the number return frames_read; }
// Initialise the codec MastCodec_MPA::MastCodec_MPA( MastMimeType *type) : MastCodec(type) { // Set default values this->samplerate = MPA_DEFAULT_SAMPLERATE; this->channels = MPA_DEFAULT_CHANNELS; // Initialise twolame this->twolame = twolame_init(); if (this->twolame==NULL) { MAST_FATAL( "Failed to initialise TwoLame" ); } // Configure twolame if (twolame_set_num_channels( this->twolame, this->channels )) { MAST_WARNING( "Failed to set number of input channels" ); } if (twolame_set_in_samplerate( this->twolame, this->samplerate )) { MAST_WARNING( "Failed to set number of input samplerate" ); } // Apply MIME type parameters to the codec this->apply_mime_type_params( type ); // Get TwoLAME ready to go... twolame_init_params( this->twolame ); }
// Callback called by JACK when jackd is shutting down static void shutdown_callback(void *arg) { MAST_WARNING("MAST quitting because jackd is shutting down" ); // Signal the main thead to stop mast_stop_running(); }
void MastTool::set_payload_size_limit( char const* size_limit_str ) { int size_limit = atoi( size_limit_str ); if (size_limit <= 1) MAST_WARNING( "Invalid payload size: %d", size_limit); this->payload_size_limit = size_limit; }
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; }
void MastTool::set_payloadtype_index( int idx ) { // Lookup the payload type PayloadType* pt = rtp_profile_get_payload( profile, idx ); if (pt==NULL) MAST_WARNING("Failed to get payload type for index %d", idx); this->payloadtype = pt; // Store it this->payloadtype_index = idx; MAST_INFO( "Payload type index: %d", idx ); // Apply it to the session if (rtp_session_set_send_payload_type( session, idx )) { MAST_FATAL("Failed to set session payload type index"); } }
void MastSendTool::prepare() { // Display some information about the chosen payload type MAST_INFO( "Sending SSRC: 0x%x", session->snd.ssrc ); MAST_INFO( "Input Format: %d Hz, %s", samplerate, channels==2 ? "Stereo" : "Mono"); mimetype->print(); // Load the codec if (codec != NULL) MAST_WARNING("Codec has already been created" ); codec = MastCodec::new_codec( mimetype ); if (codec == NULL) MAST_FATAL("Failed to get create codec" ); MAST_INFO( "Output Format: %d Hz, %s", codec->get_samplerate(), codec->get_channels()==2 ? "Stereo" : "Mono"); // Work out the payload type to use if (strcmp("MPA", codec->get_type())==0) { // MPEG Audio is a special case this->set_payloadtype_index( RTP_MPEG_AUDIO_PT ); payloadtype->channels = codec->get_channels(); } else { // Ask oRTP for the index int index = ::rtp_profile_find_payload_number( profile, codec->get_type(), codec->get_samplerate(), codec->get_channels() ); if ( index<0 ) MAST_FATAL("Failed to get payload type information from oRTP"); this->set_payloadtype_index( index ); } // Calculate the packet size frames_per_packet = codec->frames_per_packet( payload_size_limit ); if (frames_per_packet<=0) MAST_FATAL( "Invalid number of samples per packet" ); // Create audio buffers input_buffer = new MastAudioBuffer( frames_per_packet, samplerate, channels ); if (input_buffer == NULL) MAST_FATAL("Failed to create audio input buffer"); //resampled_buffer = new MastAudioBuffer( frames_per_packet, codec->get_samplerate(), codec->get_channels() ); //if (resampled_buffer == NULL) MAST_FATAL("Failed to create resampled audio buffer"); // Allocate memory for the packet buffer payload_buffer = (u_int8_t*)malloc( payload_size_limit ); if (payload_buffer == NULL) MAST_FATAL("Failed to allocate memory for payload buffer"); }
// Shut down jack related stuff static void deinit_jack( jack_client_t *client ) { // Leave the Jack graph if (jack_client_close(client)) { MAST_WARNING("Failed to close jack client"); } // Free the coversion buffer if (g_interleavebuf) { free( g_interleavebuf ); g_interleavebuf = NULL; } // Free up the ring buffer if (g_ringbuffer) { jack_ringbuffer_free( g_ringbuffer ); g_ringbuffer = NULL; } pthread_cond_destroy(&g_ringbuffer_cond); pthread_mutex_destroy(&g_ringbuffer_cond_mutex); }
int main(int argc, char **argv) { MastTool* tool = NULL; mblk_t* packet = NULL; mblk_t* body = NULL; PayloadType* pt = NULL; int payload_size = 0; // Create an RTP session tool = new MastTool( MAST_TOOL_NAME, RTP_SESSION_RECVONLY ); if (tool==NULL) return -1; // Parse the command line arguments // and configure the session parse_cmd_line( argc, argv, tool->get_session() ); // Setup signal handlers mast_setup_signals(); // Recieve a single packet packet = tool->wait_for_rtp_packet(); if (packet == NULL) MAST_FATAL("Failed to receive a packet"); body = packet->b_cont; payload_size = (body->b_wptr - body->b_rptr); // Display information about the packet received printf("\n"); printf("RTP Header\n"); printf("==========\n"); printf("Payload type : %u\n", rtp_get_payload_type( packet ) ); printf("Payload size : %u bytes\n", payload_size ); printf("Sequence Number : %u\n", rtp_get_seqnumber( packet ) ); printf("Timestamp : %u\n", rtp_get_timestamp( packet ) ); printf("SSRC Identifier : %x\n", rtp_get_ssrc( packet ) ); printf("Marker Bit : %s\n", rtp_get_markbit( packet ) ? "Set" : "Not Set"); printf("\n"); // Lookup the payload type pt = rtp_profile_get_payload( tool->get_profile(), rtp_get_payload_type( packet ) ); if (pt == NULL) { MAST_WARNING( "Payload type %u isn't registered with oRTP", rtp_get_payload_type( packet ) ); } else { const char* mime_major = "?"; printf("Payload Details\n"); printf("===============\n"); if (pt->type==PAYLOAD_AUDIO_CONTINUOUS) mime_major = "audio"; else if (pt->type==PAYLOAD_AUDIO_PACKETIZED) mime_major = "audio"; else if (pt->type==PAYLOAD_VIDEO) mime_major = "video"; printf("Mime Type : %s/%s\n", mime_major, pt->mime_type); if (pt->clock_rate) printf("Clock Rate : %u Hz\n", pt->clock_rate); if (pt->channels) printf("Channels : %u\n", pt->channels); if (pt->bits_per_sample) printf("Bits per Sample : %u\n", pt->bits_per_sample); if (pt->normal_bitrate) { printf("Normal Bitrate : %u kbps\n", (pt->normal_bitrate/1000)); printf("Packet duration : %u ms\n", (payload_size*1000)/(pt->normal_bitrate/8) ); } if (pt->recv_fmtp) printf("Recieve FMTP : %s\n", pt->recv_fmtp); if (pt->send_fmtp) printf("Send FMTP : %s\n", pt->send_fmtp); printf("\n"); } // Parse the MPEG Audio header if (rtp_get_payload_type( packet ) == RTP_MPEG_AUDIO_PT) { /* FIXME: check fragment offset header (see rfc2250) */ unsigned char* mpa_ptr = body->b_rptr + 4; MPA_Header mh; printf("MPEG Audio Header\n"); printf("=================\n"); if (!mh.parse( mpa_ptr )) { MAST_WARNING("Failed to parse MPEG Audio header"); } else { mh.debug( stdout ); } } // Close RTP session delete tool; // Success ! return 0; }
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; }