2012-11-02 23 views
12

Tôi có một ứng dụng đang phát các tệp MP3 có sẵn tại URL công khai. Thật không may là máy chủ không hỗ trợ phát trực tuyến, nhưng Android làm cho trải nghiệm người dùng khá chấp nhận được.Vấn đề về phương tiện mạng Jellybean Android

Tất cả hoạt động tốt cho tất cả các nền tảng ngoại trừ Jellybean. Khi yêu cầu MP3, JB yêu cầu cho một Phạm vi-Tiêu đề cho 10 lần. Chỉ sau lần thử thứ 10, nó dường như hoàn nguyên về hành vi cũ. Looks like this already reported issue.

Tôi tìm thấy một SO thread khác nơi giải pháp được khuyến nghị là sử dụng Mã hóa mã hóa: chunked tiêu đề. Nhưng ngay bên dưới có một nhận xét rằng điều này không hiệu quả.

Hiện tại tôi không có quyền kiểm soát bất kỳ tiêu đề phản hồi nào ở trên, nhưng cho đến khi tôi có thể làm điều đó, tôi đã nghĩ để tìm kiếm giải pháp thay thế ở phía máy khách. (Mặc dù vậy, tôi chỉ có thể trả về một Phạm vi Nội dung chứa các chỉ mục từ 0 đến Độ dài Nội dung - 1. Phạm vi Nội dung: byte 0-3123456/3123457).

Những gì tôi đã cố gắng để làm là để thực hiện một giả trực tuyến tại phía khách hàng bởi:

  1. mở thêm một input stream cho MP3.
  2. Giải mã các byte đến bằng cách sử dụng JLayer. Tôi tìm thấy giải mã tại this link.
  3. Gửi các byte mảng được giải mã tới một StreamTrack Audio_ack đã phát.

Các đoạn mã mà không được giải mã có thể được tìm thấy ở đó, tôi đã chỉ sửa đổi nó để nó sẽ nhận được một InputStream:

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); 
     } 
    } 

Tôi yêu cầu các byte được giải mã trong khối thời gian: bắt đầu với (0, 5000) vì vậy tôi sẽ có một mảng lớn hơn để chơi lúc đầu, sau đó tôi yêu cầu các mảng byte tiếp theo kéo dài hơn một giây: (5000, 1000), (6000, 1000), (7000, 1000), v.v.

Giải mã đủ nhanh và được thực hiện trong một chuỗi khác và khi mảng byte được giải mã khả dụng, tôi đang sử dụng hàng đợi chặn ghi nó vào AudioTrack đang phát trong một chuỗi khác.

Vấn đề là phát lại không trơn tru vì các đoạn không liên tục trong một rãnh (mỗi đoạn liên tục, nhưng được thêm vào trong kết quả AudioTrack khi phát lại một cách cẩu thả).

Để kết thúc:

  1. Nếu bạn đã tình cờ gặp vấn đề Jellybean này, làm thế nào bạn giải quyết nó?
  2. Nếu có ai trong số các bạn thử cách tiếp cận của tôi, tôi đang làm gì sai trong mã trên? Nếu đây là giải pháp bạn đã sử dụng, tôi có thể xuất bản phần còn lại của mã.

Cảm ơn!

Trả lời

2

Có vẻ như bạn đang cố gắng phát triển loại phát trực tuyến của riêng mình. Điều này có thể bị phát lại bị gián đoạn hoặc bị gián đoạn vì bạn phải cố gắng truyền thông tin liên tục ra khỏi byte để đọc.

Về cơ bản, bạn sẽ phải tính đến tất cả các tình huống mà một ứng dụng phát trực tuyến bình thường sẽ xử lý.Ví dụ, đôi khi một số khối có thể bị mất hoặc bị mất trong quá trình truyền; đôi khi phát lại âm thanh có thể bắt kịp quá trình tải xuống; cpu bắt đầu tụt hậu ảnh hưởng đến phát lại; v.v.

Một điều cần nghiên cứu nếu bạn muốn tiếp tục con đường này sẽ là cửa sổ trượt thực thi, về cơ bản là một kỹ thuật trừu tượng để cố gắng duy trì kết nối mạng luôn hoạt động và linh hoạt. Bạn sẽ có thể tìm thấy một số ví dụ thông qua google, đây là một nơi để bắt đầu: http://en.wikipedia.org/wiki/Sliding_window_protocol

Edit: Một cách giải quyết có thể giúp bạn cho đến khi điều này được cố định sẽ được bao gồm mã nguồn cho MediaPlayer.javaAudioManager.java từ SDK < 16 vào dự án của bạn và xem điều đó có giải quyết được vấn đề không. Nếu bạn không có mã nguồn, bạn có thể tải xuống nó bằng Trình quản lý SDK.

+0

Cảm ơn bạn đã trả lời ... Tôi không muốn làm theo cách tiếp cận này cho dự án tôi cần, nhưng nếu một ngày nào đó tôi sẽ có thời gian rảnh, tôi có thể thử điều này cho mục đích giáo dục. Vì vậy, các câu hỏi mở vẫn tồn tại (Tất cả đều hoạt động tốt cho tất cả các nền tảng ngoại trừ JellyBean. Khi yêu cầu MP3, JB yêu cầu cho một Phạm vi-Header cho 10 lần. Chỉ sau khi nỗ lực thứ 10 nó dường như trở lại hành vi cũ.) Nếu bạn gặp phải vấn đề này, bạn đã khắc phục điều này như thế nào? Đó là một cái gì đó từ phía máy chủ hoặc là nó phía khách hàng? – gunar

+0

Bạn có thể bao gồm mã của mình cho dòng này không: "Khi yêu cầu MP3, JB yêu cầu cho một Phạm vi-Tiêu đề 10 lần. Chỉ sau lần thử thứ 10 nó có vẻ hoàn nguyên về hành vi cũ". – Matt

+0

Tôi không thêm bất kỳ mã nào cho JB để yêu cầu Phạm vi tiêu đề, vui lòng xem [vấn đề Android được đính kèm] (https://code.google.com/p/android/issues/detail?id=35790). Tất cả đều liên quan đến nó. – gunar

1

AudioTrack chặn tự nhiên từ tài liệu (Will block until all data has been written to the audio mixer.). Tôi không chắc chắn nếu bạn đang đọc từ các tập tin và ghi vào AudioTrack trong cùng một chủ đề; nếu có, thì tôi khuyên bạn nên tạo một chuỗi cho AudioTrack.

Các vấn đề liên quan