2012-11-02 1 views
12

공개 URL에서 사용할 수있는 MP3 파일을 재생하는 애플리케이션이 있습니다. 불행하게도 서버는 스트리밍을 지원하지 않지만 안드로이드는 사용자 경험을 상당히 받아들입니다.Android JellyBean 네트워크 미디어 문제

JellyBean을 제외한 모든 플랫폼에서 모두 정상적으로 작동합니다. MP3를 요청할 때 JB는 Range-Header를 10 번 요청합니다. 10 번째 시도 후에 만 ​​이전 행동으로 되돌아가는 것처럼 보입니다. Looks like this already reported issue.

SO thread 해결책을 권장하는 곳에서 Tranfer-Encoding : chunked 헤더를 사용하는 것이 좋습니다. 그러나 바로 아래에는 이것이 작동하지 않는다는 의견이 있습니다.

지금까지는 응답 헤더를 제공 할 수있는 권한이 전혀 없었지만이를 수행 할 수있을 때까지 클라이언트 측에서 대안을 찾아야한다고 생각했습니다. (그렇다고해도 0에서 Content-Length - 1까지의 인덱스를 포함하는 Content-Range 만 반환 할 수 있습니다. 예 : Content-Range : 0-3123456/3123457 바이트). 내가 할 노력은 무엇

구현하는 것입니다 의사 스트리밍 클라이언트 측에서 :

  1. 를 열고 MP3에 입력 스트림.
  2. JLayer를 사용하여 들어오는 바이트를 디코딩합니다. 디코딩을 this link에서 찾았습니다.
  3. 이미 재생할 수있는 stream_mode AudioTrack에 디코딩 된 배열 바이트를 보냅니다. 나는 시간의 덩어리에서 디코딩 된 바이트를 요청하고

    public byte[] decode(InputStream inputStream, int startMs, int maxMs) throws IOException { 
         ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024); 
    
         float totalMs = 0; 
         boolean seeking = true; 
    
         try { 
          Bitstream bitstream = new Bitstream(inputStream); 
          Decoder decoder = new Decoder(); 
    
          boolean done = false; 
          while (!done) { 
           Header frameHeader = bitstream.readFrame(); 
           if (frameHeader == null) { 
            done = true; 
           } else { 
            totalMs += frameHeader.ms_per_frame(); 
    
            if (totalMs >= startMs) { 
             seeking = false; 
            } 
    
            if (!seeking) { 
             // logger.debug("Handling header: " + frameHeader.layer_string()); 
             SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream); 
    
             if (output.getSampleFrequency() != 44100 || output.getChannelCount() != 2) { 
              throw new IllegalArgumentException("mono or non-44100 MP3 not supported"); 
             } 
    
             short[] pcm = output.getBuffer(); 
             for (short s : pcm) { 
              outStream.write(s & 0xff); 
              outStream.write((s >> 8) & 0xff); 
             } 
            } 
    
            if (totalMs >= (startMs + maxMs)) { 
             done = true; 
            } 
           } 
           bitstream.closeFrame(); 
          } 
    
          return outStream.toByteArray(); 
         } catch (BitstreamException e) { 
          throw new IOException("Bitstream error: " + e); 
         } catch (DecoderException e) { 
          throw new IOException("Decoder error: " + e); 
         } 
        } 
    

    :로 시작하는이 InputStream를받을 수 있도록

디코딩을 수행하는 코드의 조각이 발견 될 수있다, 나는 단지 그것을 수정 한 (5000, 1000), (6000, 1000), (7000, 1000) 등의 순서로 다음 바이트 배열을 요청할 것입니다.

디코딩 속도가 빠르며 다른 스레드에서 처리되고 디코딩 된 바이트 배열을 사용할 수있게되면 블로킹 큐를 사용하여 다른 thread로 재생 중의 AudioTrack에 기입 해주세요.

문제는 트랙에서 청크가 연속적이지 않으므로 매끄럽지 않습니다 (각 청크는 연속이지만 AudioTrack에 추가하면 부 자연스러운 재생이 발생 함).

마무리하려면 :

  1. 이 젤리 빈 문제로 충돌 한 경우, 어떻게 그것을 해결 했습니까?
  2. 내 접근 방식을 시도한 사람이 있으면 위 코드에서 무엇을 잘못하고 있습니까? 이 솔루션을 사용했다면 나머지 코드를 게시 할 수 있습니다.

고마워요!

답변

2

자신의 스트리밍 유형을 개발하려는 것 같습니다. 읽을 때 바이트가 부족한 상태에서 연속적인 정보 파이핑을 시도해야하기 때문에 막힘 또는 중단 된 재생이 발생할 수 있습니다.

기본적으로 일반 스트리밍 클라이언트가 처리하는 모든 상황을 고려해야합니다.예를 들어, 일부 블록이 전송 중에 삭제되거나 손실되는 경우가 있습니다. 때때로 오디오 재생이 다운로드를 따라 잡을 수 있습니다. 재생에 영향을 미치는 CPU가 지연되기 시작합니다.

이 경로를 계속 진행하려면 슬라이딩 윈도우 구현이 필요합니다. 본질적으로 네트워크 연결을 항상 활성 및 유동적으로 유지하려고하는 추상적 인 기술입니다. http://en.wikipedia.org/wiki/Sliding_window_protocol

편집 :이가 해결 될 때까지 SDK < 16 MediaPlayer.javaAudioManager.java에 대한 소스 코드를 포함하는 것입니다 당신이 도움이 될 한 가지 해결 방법 당신은 구글을 ​​통해 몇 가지 예를 찾을 수 있어야합니다, 여기 시작하는 곳입니다 문제가 해결되는지 확인하십시오. 소스 코드가 없으면 SDK 관리자를 사용하여 다운로드 할 수 있습니다.

+0

응답 해 주셔서 감사합니다 ... 필자는 필요한 프로젝트에 대해이 접근법을 따르고 싶지 않지만 언젠가는 여가 시간을 갖기 위해 교육적인 목적으로이 방법을 시도 할 것입니다. 열린 질문은 여전히 ​​유효합니다 (JellyBean을 제외한 모든 플랫폼에서 정상적으로 작동합니다.) MP3를 요청할 때 JB는 Range-Header를 10 번 요청합니다. 10 번째 시도 후에 만 ​​이전 동작으로 되돌아갑니다.) 당신이 이것에 부딪쳤다면, 어떻게 이것을 고치셨습니까? 그것은 서버 측에서나 클라이언트 쪽에서였습니까? – gunar

+0

이 줄에 코드를 포함 할 수 있습니까? "MP3를 요청할 때 JB는 Range-Header를 10 회 요청합니다. 10 번째 시도 후에 만 ​​이전 동작으로 되돌아갑니다." – Matt

+0

JB가 Range-Header를 요청하는 코드를 추가하지 않았습니다. [Android 관련 문제] (https://code.google.com/p/android/issues/detail?id=35790)를 참조하십시오. 그것은 그것과 관련이 있습니다. – gunar

1

AudioTrack은 (Will block until all data has been written to the audio mixer.) 자연 차단 기능을 사용하고 있습니다. 파일에서 읽고 AudioTrack에 같은 쓰레드로 쓰고 있는지 확실하지 않습니다. 그렇다면 AudioTrack 용 스레드를 만들 것을 제안합니다.