/** * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ * * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). * * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 3.0 of the License, or (at your option) any later * version. * * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. * */ package org.bigbluebutton.voiceconf.red5.media; import java.net.DatagramSocket; import org.apache.mina.core.buffer.IoBuffer; import org.bigbluebutton.voiceconf.red5.media.transcoder.FlashToSipTranscoder; import org.bigbluebutton.voiceconf.red5.media.transcoder.TranscodedAudioDataListener; import org.bigbluebutton.voiceconf.sip.SipConnectInfo; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IStreamListener; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.SerializeUtils; import org.slf4j.Logger; public class FlashToSipAudioStream { private final static Logger log = Red5LoggerFactory.getLogger(FlashToSipAudioStream.class, "sip"); private final FlashToSipTranscoder transcoder; private IStreamListener mInputListener; private final DatagramSocket srcSocket; private final SipConnectInfo connInfo; private String talkStreamName; private RtpStreamSender rtpSender; private TranscodedAudioListener transcodedAudioListener; public FlashToSipAudioStream(final FlashToSipTranscoder transcoder, DatagramSocket srcSocket, SipConnectInfo connInfo) { this.transcoder = transcoder; this.srcSocket = srcSocket; this.connInfo = connInfo; talkStreamName = "microphone_" + System.currentTimeMillis(); transcodedAudioListener = new TranscodedAudioListener(); transcoder.setTranscodedAudioListener(transcodedAudioListener); } public void start(IBroadcastStream broadcastStream, IScope scope) throws StreamException { if (log.isDebugEnabled()) log.debug("startTranscodingStream({},{})", broadcastStream.getPublishedName(), scope.getName()); mInputListener = new IStreamListener() { public void packetReceived(IBroadcastStream broadcastStream, IStreamPacket packet) { IoBuffer buf = packet.getData(); if (buf != null) buf.rewind(); if (buf == null || buf.remaining() == 0){ log.debug("skipping empty packet with no data"); return; } if (packet instanceof AudioData) { byte[] data = SerializeUtils.ByteBufferToByteArray(buf); // Remove the first byte as it is the codec id. transcoder.handlePacket(data, 1, data.length-1); } } }; broadcastStream.addStreamListener(mInputListener); rtpSender = new RtpStreamSender(srcSocket, connInfo); rtpSender.connect(); transcoder.start(); } public void stop(IBroadcastStream broadcastStream, IScope scope) { broadcastStream.removeStreamListener(mInputListener); if (broadcastStream != null) { broadcastStream.stop(); broadcastStream.close(); } transcoder.stop(); srcSocket.close(); } public String getStreamName() { return talkStreamName; } public class TranscodedAudioListener implements TranscodedAudioDataListener { @Override public void handleTranscodedAudioData(byte[] audioData, long timestamp) { if (audioData != null) { rtpSender.sendAudio(audioData, transcoder.getCodecId(), timestamp); } else { log.warn("Transcodec audio is null. Discarding."); } } } }