<commit_before>/*
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.impl.neomedia.rtp;

import java.io.*;
import java.util.*;

import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.rtp.*;

import net.sf.fmj.media.rtp.*;
import org.jitsi.impl.neomedia.rtcp.*;
import org.jitsi.impl.neomedia.rtp.translator.*;
import org.jitsi.service.neomedia.*;

/**
 * Implements the <tt>RTPManager</tt> interface as used by a
 * <tt>MediaStream</tt>.
 *
 * @author <NAME>
 */
public class StreamRTPManager
{
    /**
     * The <tt>MediaStream</tt> that uses this <tt>StreamRTPManager</tt>
     */
    private final MediaStream stream;

    /**
     * The <tt>RTPManager</tt> this instance is to delegate to when it is not
     * attached to an <tt>RTPTranslator</tt>.
     */
    private final RTPManager manager;

    /**
     * The <tt>RTPTranslator</tt> which this instance is attached to and which
     * forwards the RTP and RTCP flows of the <tt>MediaStream</tt> associated
     * with this instance to other <tt>MediaStream</tt>s.
     */
    private final RTPTranslatorImpl translator;

    /**
     * A map of source ssrc to {@link ResumableStreamRewriter}.
     */
    private final Map<Long, ResumableStreamRewriter> ssrcToRewriter
        = new HashMap<>();

    /**
     * The {@code RemoteClockEstimator} which tracks the remote (wall)clocks and
     * RTP timestamps of the RTP streams received by the associated
     * {@link #stream}.
     */
    private final RemoteClockEstimator _remoteClockEstimator;

    /**
     * Initializes a new <tt>StreamRTPManager</tt> instance which is,
     * optionally, attached to a specific <tt>RTPTranslator</tt> which is to
     * forward the RTP and RTCP flows of the associated <tt>MediaStream</tt> to
     * other <tt>MediaStream</tt>s.
     *
     * @param stream the <tt>MediaStream</tt> that created this
     * <tt>StreamRTPManager</tt>.
     * @param translator the <tt>RTPTranslator</tt> to attach the new instance
     * to or <tt>null</tt> if the new instance is to not be attached to any
     * <tt>RTPTranslator</tt>
     */
    public StreamRTPManager(MediaStream stream, RTPTranslator translator)
    {
        this.stream = stream;
        this.translator = (RTPTranslatorImpl) translator;
        this._remoteClockEstimator = new RemoteClockEstimator(this);

        manager = (this.translator == null) ? RTPManager.newInstance() : null;
    }

    public RemoteClock[] findRemoteClocks(long... ssrcs)
    {
        RemoteClock[] clocks = new RemoteClock[ssrcs.length];

        for (int i = 0; i < ssrcs.length; ++i)
        {
            RemoteClock clock
                = _remoteClockEstimator.getRemoteClock(ssrcs[i]);

            if (clock != null)
            {
                clocks[i] = clock;
            }
        }
        return clocks;
    }

    public RemoteClock findRemoteClock(long ssrc)
    {
        return findRemoteClocks(ssrc)[0];
    }

    public void addFormat(Format format, int payloadType)
    {
        if (translator == null)
            manager.addFormat(format, payloadType);
        else
            translator.addFormat(this, format, payloadType);
    }

    public void addReceiveStreamListener(ReceiveStreamListener listener)
    {
        if (translator == null)
            manager.addReceiveStreamListener(listener);
        else
            translator.addReceiveStreamListener(this, listener);
    }

    public void addRemoteListener(RemoteListener listener)
    {
        if (translator == null)
            manager.addRemoteListener(listener);
        else
            translator.addRemoteListener(this, listener);
    }

    public void addSendStreamListener(SendStreamListener listener)
    {
        if (translator == null)
            manager.addSendStreamListener(listener);
        else
            translator.addSendStreamListener(this, listener);
    }

    public void addSessionListener(SessionListener listener)
    {
        if (translator == null)
            manager.addSessionListener(listener);
        else
            translator.addSessionListener(this, listener);
    }

    public SendStream createSendStream(DataSource dataSource, int streamIndex)
        throws IOException,
               UnsupportedFormatException
    {
        if (translator == null)
            return manager.createSendStream(dataSource, streamIndex);
        else
            return translator.createSendStream(this, dataSource, streamIndex);
    }

    public void dispose()
    {
        if (translator == null)
            manager.dispose();
        else
            translator.dispose(this);
    }

    /**
     * Gets the {@link ResumableStreamRewriter} that is associated to the SSRC
     * passed as a parameter. If there's no {@link ResumableStreamRewriter}
     * associated with that SSRC and the create flag is set to true, then a new
     * {@link ResumableStreamRewriter} will be created.
     *
     * @param ssrc the SSRC whose associated {@link ResumableStreamRewriter} is
     * to be returned.
     *
     * @return the {@link ResumableStreamRewriter} that is associated to the
     * SSRC parameter
     */
    public ResumableStreamRewriter getResumableStreamRewriter(Long ssrc)
    {
        ResumableStreamRewriter rewriter = ssrcToRewriter.get(ssrc);
        if (rewriter == null)
        {
            rewriter = new ResumableStreamRewriter();
            ssrcToRewriter.put(ssrc, rewriter);
        }

        return rewriter;
    }

    /**
     * Gets a control of a specific type over this instance. Invokes
     * {@link #getControl(String)}.
     *
     * @param controlType a <tt>Class</tt> which specifies the type of the
     * control over this instance to get
     * @return a control of the specified <tt>controlType</tt> over this
     * instance if this instance supports such a control; otherwise,
     * <tt>null</tt>
     */<commit_msg>fix: Synchronize access to ssrcToRewriter.<commit_after>/*
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.impl.neomedia.rtp;

import java.io.*;
import java.util.*;

import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.rtp.*;

import net.sf.fmj.media.rtp.*;
import org.jitsi.impl.neomedia.rtcp.*;
import org.jitsi.impl.neomedia.rtp.translator.*;
import org.jitsi.service.neomedia.*;

/**
 * Implements the <tt>RTPManager</tt> interface as used by a
 * <tt>MediaStream</tt>.
 *
 * @author <NAME>
 */
public class StreamRTPManager
{
    /**
     * The <tt>MediaStream</tt> that uses this <tt>StreamRTPManager</tt>
     */
    private final MediaStream stream;

    /**
     * The <tt>RTPManager</tt> this instance is to delegate to when it is not
     * attached to an <tt>RTPTranslator</tt>.
     */
    private final RTPManager manager;

    /**
     * The <tt>RTPTranslator</tt> which this instance is attached to and which
     * forwards the RTP and RTCP flows of the <tt>MediaStream</tt> associated
     * with this instance to other <tt>MediaStream</tt>s.
     */
    private final RTPTranslatorImpl translator;

    /**
     * A map of source ssrc to {@link ResumableStreamRewriter}.
     */
    private final Map<Long, ResumableStreamRewriter> ssrcToRewriter
        = new HashMap<>();

    /**
     * The {@code RemoteClockEstimator} which tracks the remote (wall)clocks and
     * RTP timestamps of the RTP streams received by the associated
     * {@link #stream}.
     */
    private final RemoteClockEstimator _remoteClockEstimator;

    /**
     * Initializes a new <tt>StreamRTPManager</tt> instance which is,
     * optionally, attached to a specific <tt>RTPTranslator</tt> which is to
     * forward the RTP and RTCP flows of the associated <tt>MediaStream</tt> to
     * other <tt>MediaStream</tt>s.
     *
     * @param stream the <tt>MediaStream</tt> that created this
     * <tt>StreamRTPManager</tt>.
     * @param translator the <tt>RTPTranslator</tt> to attach the new instance
     * to or <tt>null</tt> if the new instance is to not be attached to any
     * <tt>RTPTranslator</tt>
     */
    public StreamRTPManager(MediaStream stream, RTPTranslator translator)
    {
        this.stream = stream;
        this.translator = (RTPTranslatorImpl) translator;
        this._remoteClockEstimator = new RemoteClockEstimator(this);

        manager = (this.translator == null) ? RTPManager.newInstance() : null;
    }

    public RemoteClock[] findRemoteClocks(long... ssrcs)
    {
        RemoteClock[] clocks = new RemoteClock[ssrcs.length];

        for (int i = 0; i < ssrcs.length; ++i)
        {
            RemoteClock clock
                = _remoteClockEstimator.getRemoteClock(ssrcs[i]);

            if (clock != null)
            {
                clocks[i] = clock;
            }
        }
        return clocks;
    }

    public RemoteClock findRemoteClock(long ssrc)
    {
        return findRemoteClocks(ssrc)[0];
    }

    public void addFormat(Format format, int payloadType)
    {
        if (translator == null)
            manager.addFormat(format, payloadType);
        else
            translator.addFormat(this, format, payloadType);
    }

    public void addReceiveStreamListener(ReceiveStreamListener listener)
    {
        if (translator == null)
            manager.addReceiveStreamListener(listener);
        else
            translator.addReceiveStreamListener(this, listener);
    }

    public void addRemoteListener(RemoteListener listener)
    {
        if (translator == null)
            manager.addRemoteListener(listener);
        else
            translator.addRemoteListener(this, listener);
    }

    public void addSendStreamListener(SendStreamListener listener)
    {
        if (translator == null)
            manager.addSendStreamListener(listener);
        else
            translator.addSendStreamListener(this, listener);
    }

    public void addSessionListener(SessionListener listener)
    {
        if (translator == null)
            manager.addSessionListener(listener);
        else
            translator.addSessionListener(this, listener);
    }

    public SendStream createSendStream(DataSource dataSource, int streamIndex)
        throws IOException,
               UnsupportedFormatException
    {
        if (translator == null)
            return manager.createSendStream(dataSource, streamIndex);
        else
            return translator.createSendStream(this, dataSource, streamIndex);
    }

    public void dispose()
    {
        if (translator == null)
            manager.dispose();
        else
            translator.dispose(this);
    }

    /**
     * Gets the {@link ResumableStreamRewriter} that is associated to the SSRC
     * passed as a parameter. If there's no {@link ResumableStreamRewriter}
     * associated with that SSRC and the create flag is set to true, then a new
     * {@link ResumableStreamRewriter} will be created.
     *
     * @param ssrc the SSRC whose associated {@link ResumableStreamRewriter} is
     * to be returned.
     *
     * @return the {@link ResumableStreamRewriter} that is associated to the
     * SSRC parameter
     */
    public ResumableStreamRewriter getResumableStreamRewriter(Long ssrc)
    {
        synchronized (ssrcToRewriter)
        {
            ResumableStreamRewriter rewriter = ssrcToRewriter.get(ssrc);
            if (rewriter == null)
            {
                rewriter = new ResumableStreamRewriter();
                ssrcToRewriter.put(ssrc, rewriter);
            }
            return rewriter;
        }
    }

    /**
     * Gets a control of a specific type over this instance. Invokes
     * {@link #getControl(String)}.
     *
     * @param controlType a <tt>Class</tt> which specifies the type of the
     * control over this instance to get
     * @return a control of the specified <tt>controlType</tt> over this
     * instance if this instance supports such a control; otherwise,
     * <tt>null</tt>
     */
{'fraction_non_alphanumeric': 0.09285277947464875, 'fraction_numerical': 0.0015271838729383018, 'mean_word_length': 2.5793932768515986, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7585345', 'n_tokens_mistral': 3759, 'n_tokens_neox': 3631, 'n_words': 1096}