2012-07-23 13 views
19

मेरे पास एक ऑडियो स्ट्रीमिंग ऐप है, जो स्थानीय प्रॉक्सी सर्वर चलाता है। स्थानीय प्रॉक्सी सर्वर एक इंटरनेट स्ट्रीमिंग स्रोत के लिए एक HTTP कनेक्शन बनाता है, स्थानीय स्तर पर स्ट्रीमिंग डेटा प्राप्त करता है और बफर करता है। फिर, अनुप्रयोग में अंदर, मैं MediaPlayer का उपयोग स्थानीय प्रॉक्सी सर्वर से कनेक्ट करने के लिए, (Android उपकरणों और विभिन्न OS संस्करण के साथ बहुत - 1.5 ... 4.0) विधिएंड्रॉइड मीडिया प्लेयर - रेंज अनुरोध को अक्षम कैसे करें? (नेक्सस 7 पर टूटी हुई ऑडियो स्ट्रीमिंग)

mediaPlayer.setDataSource(...); // the url of the local proxy server 

सब कुछ ठीक था का उपयोग कर, नेक्सस 7 रिलीज तक।

नेक्सस 7 में, मीडिया प्लेयर स्थानीय प्रॉक्सी सर्वर से स्रोत चलाने से इंकार कर देता है।

जब मैंने लॉग पर एक नज़र डाली, ऐसा लगता है कि मीडियाप्लेयर आंतरिक रूप से रेंज अनुरोधों का उपयोग करता है। मेरा स्थानीय प्रॉक्सी सर्वर इसे संभाल नहीं करता है। यह HTTP/1.0 200 ठीक है और डेटा देता है। हालांकि, मीडिया प्लेयर की तरह नहीं है और एक अपवाद फेंकता है:

Caused by: libcore.io.ErrnoException 
?:??: W/?(?): [ 07-18 00:08:35.333 4962: 5149 E/radiobee ] 
?:??: W/?(?): : sendto failed: ECONNRESET (Connection reset by peer) 
?:??: W/?(?): at libcore.io.Posix.sendtoBytes(Native Method) 
?:??: W/?(?): at libcore.io.Posix.sendto(Posix.java:146) 
?:??: W/?(?): at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java: 
?:??: W/?(?): at libcore.io.IoBridge.sendto(IoBridge.java:473) 
We requested a content range, but server didn't support that. (responded with 200) 

http चश्मा के मुताबिक, अगर सर्वर HTTP के साथ प्रतिक्रिया/1.0 के बजाय 1.1, ग्राहक एक सीमा अनुरोध आग नहीं होना चाहिए (1.0 वैसे भी इसका समर्थन नहीं करता है),

यदि सर्वर रेंज अनुरोध का समर्थन नहीं करता है, तो यह ठीक होना चाहिए, अगर यह 200 ओके (और यही वह है जो मैं कर रहा हूं) का जवाब देता हूं, लेकिन मीडियाप्लेयर कार्यान्वयन नेक्सस 7 पर यह पसंद नहीं है।

मैं इस सूत्र पर एक दृष्टि डाली: HTTP: How should I respond to "Range: bytes=" when Range is unsupported?

, जहां वे दावा करते हैं कि 200 ठीक से प्रतिक्रिया काफी अच्छा होना चाहिए, लेकिन दुर्भाग्य से यह मदद नहीं करता है।

मुझे यकीन नहीं है कि यह जेली बीन, या नेक्सस 7 कार्यान्वयन के साथ एक समस्या है, लेकिन यह अभी भी मेरे लिए एक समस्या है जिसे मुझे हल करना है।

फिर, एक ही ऐप का उपयोग करके, अन्य एंड्रॉइड डिवाइस पर कोई रेंज अनुरोध नहीं है। किसी कारण से ये सीमा अनुरोध अब Nexus 7 पर हो रहे हैं। (यह अन्य एंड्रॉइड डिवाइसों पर भी हो सकता है, लेकिन फिर से, अब तक मेरे साथ कभी नहीं हुआ)।

मीडियाप्लेयर के लिए रेंज अनुरोधों को अक्षम करने का कोई भी संभावित तरीका?

यदि कोई नहीं है, तो क्या कोई मेरे प्रॉक्सी सर्वर तर्क के लिए त्वरित समाधान सुझा सकता है (यदि यह रेंज अनुरोध प्राप्त होता है तो उसे वापस लौटना होगा?), यदि संभव हो तो मेरा अन्य तर्क बदलने के बिना?

ऐसा लगता है कि मुझे "HTTP/1.0 206 ठीक \ r \ n पार्टिकल सामग्री \ r \ n \ r \ n" जैसे कुछ वापस करना होगा, लेकिन शायद आंशिक सामग्री के अंत में कुछ मूल्य होना चाहिए - नहीं सुनिश्चित करें कि यह क्या होना चाहिए।

आपकी सहायता की सराहना की जाएगी।

धन्यवाद ..

+2

मैं इसकी पुष्टि कर सकता हूं कि यह जेली बीन मुद्दा (न केवल Nexus 7) है। यह विभिन्न नेक्सस उपकरणों पर भी हुआ, हाल ही में आइसक्रीम सैंडविच से जेली बीन तक अपडेट किया गया। क्या कोई भी जेली बीन में स्थानीय प्रॉक्सी सर्वर के खिलाफ मीडियाप्लेयर का उपयोग करने में सक्षम था? – user1512464

+0

इस मुद्दे की पुष्टि भी कर सकते हैं (जेली बीन पर)। हम प्रॉक्सी का उपयोग नहीं कर रहे हैं, हालांकि, हम सीधे मीडिया प्लेयर के माध्यम से ऑडियो स्ट्रीम तक पहुंचते हैं। – pulse00

+0

यह जेली बीन में एक रिग्रेशन की तरह दिखता है। मैंने बगट्रैकर पर कोई समस्या बनाई है: https://code.google.com/p/android/issues/detail?id=35790 – pulse00

उत्तर

8

मैं एक बड़े पैमाने पर ऑडियो स्ट्रीमिंग ऐप्लिकेशन पर काम (जो MediaPlayer के लिए ऑडियो स्ट्रीम करने के लिए एक स्थानीय होस्ट HTTP प्रॉक्सी का इस्तेमाल) और मैं जितनी जल्दी इस मुद्दे में भाग के रूप में मैं में एक JellyBean डिवाइस मिला मेरी Google I/O 2012 में हाथ

जब गुणवत्ता विभिन्न उपकरणों (और हमारे स्वचालित क्रैश लॉग और उपयोगकर्ता द्वारा सबमिट किए गए लॉग से प्राप्त जानकारी के साथ) की गुणवत्ता का परीक्षण करते हैं, तो हमने देखा कि कुछ मीडियाप्लेयर कार्यान्वयनों में मैं एक अनियमित (और कभी-कभी मनोवैज्ञानिक) तरीके से व्यवहार करता हूं।

बहुत अधिक विस्तार के बिना, मैंने यही देखा: कुछ कार्यान्वयन एक ही यूआरएल के लिए कई अनुरोध (कुछ बार 5+) करेंगे। ये अनुरोध एक दूसरे से थोड़ा अलग थे कि प्रत्येक एक अलग बाइट रेंज के लिए था (आमतौर पर पहले या आखिरी 128 बाइट्स के लिए)। निष्कर्ष यह था कि मीडियाप्लेयर एम्बेडेड मेटाडेटा खोजने की कोशिश कर रहा था, फिर कुछ बिंदु के बाद यह हार जाएगा और केवल एक नियमित गैर-रेंज अनुरोध करेगा।

स्टॉक जेलीबीन मीडियाप्लेयर कार्यान्वयन स्टॉक नहीं है, यह सिर्फ एंड्रॉइड पर मीडिया ढांचे के बेकार और सामान्य विखंडन का एक उदाहरण है। हालांकि, इसके बाद के संस्करण स्थिति का हल भी था JellyBean समस्या का समाधान है, और वह यह है कि:

अपने स्थानीय प्रॉक्सी के साथ chunked encoding

यह एक स्थानांतरित करें-एन्कोडिंग के साथ सामग्री-लंबाई हेडर की जगह जवाब है: chunked हैडर। इसका मतलब है कि अनुरोध करने वाला ग्राहक संसाधन की कुल लंबाई को नहीं जानता है और इस प्रकार कोई रेंज-अनुरोध नहीं कर सकता है, इसे केवल प्राप्त होने वाले हिस्सों से निपटना होगा।

जैसे मैंने कहा कि यह एक हैक है, लेकिन यह काम करता है। यह इसके दुष्प्रभावों के बिना नहीं है: मीडिया प्लेयर बफर प्रगति गलत होगी क्योंकि यह ऑडियो की लंबाई (उनमें से एक है) नहीं जानता है, ताकि आप अपने स्वयं के बफरिंग गणना का उपयोग कर सकें (आप स्ट्रीमिंग कर रहे हैं कहीं से आपकी प्रॉक्सी से मीडियाप्लेयर तक, सही? तो आप कुल लंबाई जानेंगे)।

+0

यह एक समस्या का एक दिलचस्प दृष्टिकोण है जिसे मैंने जेली बीन डिवाइस पर भी चलाया है । मेरा सर्वर एमपी 3 स्ट्रीम करता है और रेंज अनुरोधों का जवाब देता है। MediaPlayer अधिकांश फ़ाइलों के लिए एक ही अनुरोध करता है, लेकिन कुछ फाइलें इस अनियमित व्यवहार का कारण बनती हैं (अनुरोधों की संख्या और उनके बाइट ऑफसेट अलग-अलग होते हैं, लेकिन किसी दिए गए फ़ाइल के लिए व्यवहार निर्धारिती लगता है)। चंकित स्थानांतरण-एन्कोडिंग मदद नहीं की। मीडियाप्लेयर ने पहली प्रतिक्रिया के तुरंत बाद एक रेंज अनुरोध किया और उस हेडर को अनदेखा कर दिया। पैकेट ट्रेस: ​​http://pastebin.com/LiN6sKYH क्या मुझे कुछ याद आ रही है? क्या स्ट्रीमिंग एंडपॉइंट स्थानीय होना चाहिए? –

11

हमने अंततः इसे एक साफ तरीके से हल किया है। हमारे मामले में हमारे पास स्ट्रीमिंग सर्वर पर पूर्ण नियंत्रण है, लेकिन मुझे लगता है कि आप इसे स्थानीय प्रॉक्सी के साथ भी कर सकते हैं। Build.VERSION_CODES.ICE_CREAM_SANDWICH के बाद से MediaPlayer ऑब्जेक्ट के लिए हेडर सेट करना संभव है। चूंकि हमारा ऐप उपयोगकर्ता को ऑडियो स्ट्रीम के अंदर खोजने में सक्षम बनाता है, हमने क्लाइंट पर Range शीर्षलेख लागू किया है। यदि सर्वर उचित शीर्षलेखों के साथ प्रतिक्रिया करता है, तो MediaPlayer स्ट्रीम का अनुरोध करने के लिए कई बार कोशिश नहीं करेगा।

है यही कारण है कि हमारे सर्वर हेडर एंड्रॉयड ग्राहक के लिए अब की तरह लग रहे:

Content-Type: audio/mpeg 
Accept-Ranges: bytes 
Content-Length: XXXX 
Content-Range: bytes XXX-XXX/XXX 
Status: 206 

महत्वपूर्ण हिस्सा 206 स्थिति कोड (आंशिक सामग्री) है। यदि आप यह हेडर नहीं भेजते हैं, तो एंड्रॉइड क्लाइंट स्रोत का दोबारा अनुरोध करने का प्रयास करेगा, इससे कोई फर्क नहीं पड़ता।

यदि आपका खिलाड़ी स्ट्रीम में जाने की अनुमति नहीं देता है, तो आप हमेशा Range शीर्षलेख 0-some arbitrary large number पर सेट कर सकते हैं।

6

जब आप चाहते हैं या छोड़ सकते हैं या कनेक्शन खो जाता है और MediaPlayer प्रॉक्सी सर्वर के लिए पुन: कनेक्ट रहता है, तो आप स्थिति के साथ इस प्रतिक्रिया भेजना होगा 206 आप ग्राहक से अनुरोध करता है और सीमा (int) प्राप्त करने के बाद।

String headers += "HTTP/1.0 206 OK\r\n"; 
headers += "Content-Type: audio/mpeg\r\n"; 
headers += "Accept-Ranges: bytes\r\n"; 
headers += "Content-Length: " + (fileSize-range) + "\r\n"; 
headers += "Content-Range: bytes "+range + "-" + fileSize + "/*\r\n"; 
headers += "\r\n"; 
संबंधित मुद्दे