0

내 프로젝트에는 여러 mp3 파일이 완전히 동기화되어 재생되는 mp3 플레이어가 있어야합니다. MediaPlayer를 사용해 보았습니다.하지만 문제는 루프에서 두 개의 mp3 파일을 시작할 때 동기화가 약간 벗어났습니다. 물론 그들은 Play()를 호출하기 전에 만들어지고 준비됩니다. 이것은 단순한 소리가 아니지만 원활하게 반복되어야하는 3-4 분 음악 파일입니다. 내가 AudioTrack 고민하고있는 순간 Monodroid (Xamarin) 여러 mp3를 동기화하는 법

, 파일이 AndroidAssets이 나는 그것의 스트림을 만들 때 ByteReader 메모리 부족 오류를 제공하기 때문에 ...

그래서 일을 더 나은 방법이있다 이 MP3 음악 동기화 재생?

감사 그렉

답변

2

지금 며칠 동안 같은 문제로 strugling되었다. 내 aproach 스트림/디코딩/MediaExtractor/MediaCodec/AudioTrack를 사용하여 MP3 파일을 재생 mutiple 스레드를했다. C#으로 작업하고 있지만 재생 중 많은 GC 활동을 관찰했습니다. 아래에서 단일 트랙에 대한 코드를 찾을 수 있습니다. 발생한 문제와 해결 방법에 대해 자세히 알아볼 수 있습니다 : How to stream data from MediaCodec to AudioTrack with Xamarin for Android.

저가형 장치에서 트랙이 동기화되지 않는 것으로 나타났습니다 (10 초에서 100 초의 지연). 문제는 audioTrack.Play()를 할 때, AudioTrack은 즉시 버퍼를 재생할 수있는 충분한 데이터를 가지고 있지 않으며, 입력 파일 포맷에 따라 mp3 프레임을 채우는 데 필요한 다른 숫자가 필요하다는 것입니다. 트랙은 다른 지연으로 시작됩니다. 이 문제를 해결하기위한 해결책은 audioTrack.Play()를 호출하는 것보다 버퍼가 충분한 바이트 (AudioTrack.GetMinBufferSize (...))를 가지고 있다는 것을 알 때까지 audioTrack.Play()를 연기하는 것입니다.

var fd = this.Resources.OpenRawResourceFd(Resource.Raw.PianoInsideMics); 

var extractor = new MediaExtractor(); 
extractor.SetDataSource(fd.FileDescriptor, fd.StartOffset, fd.Length); 
extractor.SelectTrack(0); 

var trackFormat = extractor.GetTrackFormat(0); 

var decoder = MediaCodec.CreateDecoderByType(trackFormat.GetString(MediaFormat.KeyMime)); 
decoder.Configure(trackFormat, null, null, MediaCodecConfigFlags.None); 

var thread = new Thread(() => 
{ 
    decoder.Start(); 
    var decoderInputBuffers = decoder.GetInputBuffers(); 
    var decoderOutputBuffers = decoder.GetOutputBuffers(); 

    var inputIndex = decoder.DequeueInputBuffer(-1); 
    var inputBuffer = decoderInputBuffers[inputIndex]; 
    var bufferInfo = new MediaCodec.BufferInfo(); 
    byte[] audioBuffer = null; 
    AudioTrack audioTrack = null; 

    var read = extractor.ReadSampleData(inputBuffer, 0); 
    while (read > 0) 
    { 
     decoder.QueueInputBuffer(inputIndex, 0, read, extractor.SampleTime, 
      extractor.SampleFlags == MediaExtractorSampleFlags.Sync ? MediaCodecBufferFlags.SyncFrame : MediaCodecBufferFlags.None); 

     extractor.Advance(); 

     var outputIndex = decoder.DequeueOutputBuffer(bufferInfo, -1); 
     if (outputIndex == (int) MediaCodecInfoState.OutputFormatChanged) 
     { 
      trackFormat = decoder.OutputFormat; 
     } 
     else if (outputIndex >= 0) 
     { 
      if (bufferInfo.Size > 0) 
      { 
       var outputBuffer = decoderOutputBuffers[outputIndex]; 
       if (audioBuffer == null || audioBuffer.Length < bufferInfo.Size) 
       { 
        audioBuffer = new byte[bufferInfo.Size]; 
        Debug.WriteLine("Allocated new audiobuffer: {0}", audioBuffer.Length); 
       } 

       outputBuffer.Rewind(); 
       outputBuffer.Get(audioBuffer, 0, bufferInfo.Size); 
       decoder.ReleaseOutputBuffer(outputIndex, false); 

       if (audioTrack == null) 
       { 
        var sampleRateInHz = trackFormat.GetInteger(MediaFormat.KeySampleRate); 
        var channelCount = trackFormat.GetInteger(MediaFormat.KeyChannelCount); 
        var channelConfig = channelCount == 1 ? ChannelOut.Mono : ChannelOut.Stereo; 

        audioTrack = new AudioTrack(
         Stream.Music, 
         sampleRateInHz, 
         channelConfig, 
         Encoding.Pcm16bit, 
         AudioTrack.GetMinBufferSize(sampleRateInHz, channelConfig, Encoding.Pcm16bit)*2, 
         AudioTrackMode.Stream); 

        audioTrack.Play(); 
       } 

       audioTrack.Write(audioBuffer, 0, bufferInfo.Size); 
      } 
     } 

     inputIndex = decoder.DequeueInputBuffer(-1); 
     inputBuffer = decoderInputBuffers[inputIndex]; 

     read = extractor.ReadSampleData(inputBuffer, 0); 
    } 
});