ऑडियो

Aऑडियो एक नया Android C API है, जिसे Android O रिलीज़ में पेश किया गया है. इसे बेहतरीन परफ़ॉर्मेंस वाले ऐसे ऑडियो ऐप्लिकेशन के लिए बनाया गया है जिनमें वीडियो स्ट्रीम होने और उसके दिखने के समय का अंतर कम होता है. ऐप्लिकेशन, स्ट्रीम में डेटा को पढ़कर और उसमें बदलाव करके, AAudio से कम्यूनिकेट करते हैं.

A Audio API का डिज़ाइन बेहद कम है, यह इन फ़ंक्शन का इस्तेमाल नहीं करता है:

  • ऑडियो डिवाइस की गिनती
  • ऑडियो एंडपॉइंट के बीच अपने-आप रूटिंग होना
  • फ़ाइल I/O
  • कंप्रेस किए गए ऑडियो को डिकोड किया जा रहा है
  • एक ही कॉलबैक में सभी इनपुट/स्ट्रीम का अपने-आप प्रज़ेंटेशन.

शुरू करना

C++ कोड से AAudio कॉल किया जा सकता है. अपने ऐप्लिकेशन में AAudio सुविधा सेट जोड़ने के लिए, AAudio.h हेडर फ़ाइल शामिल करें:

#include <aaudio/AAudio.h>

ऑडियो स्ट्रीम

A Audio, ऑडियो डेटा को आपके ऐप्लिकेशन और Android डिवाइस के ऑडियो इनपुट और आउटपुट के बीच ट्रांसफ़र करता है. आपका ऐप्लिकेशन ऑडियो स्ट्रीम को पढ़कर और उसमें बदलाव करके, डेटा को ट्रांसफ़र और आउट करता है. ऑडियो स्ट्रीम को AAudioStream फ़ॉर्मैट में दिखाया जाता है. रीड/राइट कॉल, ब्लॉक किए जा सकते हैं या ब्लॉक नहीं किए जा सकते.

स्ट्रीम को इन तरीकों से तय किया जाता है:

  • वह ऑडियो डिवाइस जो स्ट्रीम में डेटा का सोर्स या सिंक होता है.
  • शेयर करने वाला मोड, जो तय करता है कि किसी स्ट्रीम के पास ऐसे ऑडियो डिवाइस का खास ऐक्सेस है या नहीं जिसे कई स्ट्रीम के बीच शेयर किया जा सकता हो.
  • स्ट्रीम में ऑडियो डेटा का फ़ॉर्मैट.

ऑडियो डिवाइस

हर स्ट्रीम एक ऑडियो डिवाइस से जुड़ी होती है.

ऑडियो डिवाइस, एक हार्डवेयर इंटरफ़ेस या वर्चुअल एंडपॉइंट होता है. यह डिजिटल ऑडियो डेटा को लगातार स्ट्रीम करने के लिए, सोर्स या सिंक के तौर पर काम करता है. ऑडियो डिवाइस को भ्रमित न करें (पहले से मौजूद माइक या ब्लूटूथ हेडसेट) को उस Android डिवाइस (फ़ोन या स्मार्टवॉच) के साथ कनेक्ट करें जिस पर आपका ऐप्लिकेशन चल रहा हो.

अपने Android डिवाइस पर मौजूद ऑडियो डिवाइसों को खोजने के लिए, AudioManager तरीके getDevices() का इस्तेमाल किया जा सकता है. इस तरीके से, हर डिवाइस के type के बारे में जानकारी मिलती है.

Android डिवाइस पर, हर ऑडियो डिवाइस का एक यूनीक आईडी होता है. किसी ऑडियो स्ट्रीम को किसी ऑडियो डिवाइस से बाइंड करने के लिए, इस आईडी का इस्तेमाल किया जा सकता है. हालांकि, ज़्यादातर मामलों में आपके पास Aऑडियो को खुद चुनने के बजाय, डिफ़ॉल्ट मुख्य डिवाइस को चुनने की अनुमति देने का विकल्प होता है.

किसी स्ट्रीम के साथ जुड़े ऑडियो डिवाइस से तय होता है कि स्ट्रीम, इनपुट के लिए है या आउटपुट के लिए. एक स्ट्रीम डेटा को सिर्फ़ एक दिशा में ले जा सकती है. स्ट्रीम को परिभाषित करते समय, इसकी दिशा भी सेट की जाती है. किसी स्ट्रीम को खोलने पर, Android जांच करके यह पक्का करता है कि ऑडियो डिवाइस और स्ट्रीम की दिशा एक जैसी है या नहीं.

शेयर करने का मोड

किसी स्ट्रीम में शेयर करने का मोड होता है:

  • AAUDIO_SHARING_MODE_EXCLUSIVE का मतलब है कि स्ट्रीम के पास अपने ऑडियो डिवाइस का खास ऐक्सेस है; इस डिवाइस को किसी भी अन्य ऑडियो स्ट्रीम के लिए इस्तेमाल नहीं किया जा सकता. अगर ऑडियो डिवाइस पहले से इस्तेमाल किया जा रहा है, तो हो सकता है कि स्ट्रीम के लिए खास ऐक्सेस न मिल पाए. आम तौर पर, खास स्ट्रीम के लिए लाइव स्ट्रीमिंग करने और उसके दिखने के बीच इंतज़ार का समय कम होता है. हालांकि, स्ट्रीम के डिसकनेक्ट होने की संभावना भी ज़्यादा होती है. अगर आपको खास स्ट्रीम की ज़रूरत नहीं है, तो उन्हें तुरंत बंद कर दें, ताकि दूसरे ऐप्लिकेशन डिवाइस को ऐक्सेस कर सकें. खास स्ट्रीम के लिए, लाइव स्ट्रीमिंग करने और उसके दिखने के बीच इंतज़ार का समय सबसे कम रहता है.
  • AAUDIO_SHARING_MODE_SHARED, Aऑडियो को ऑडियो मिक्स करने की अनुमति देता है. ऑडियो, एक ही डिवाइस पर असाइन की गई सभी शेयर की गई स्ट्रीम को मिला देता है.

स्ट्रीम बनाते समय, शेयर करने वाले मोड को खास तौर पर सेट किया जा सकता है. डिफ़ॉल्ट रूप से, शेयर करने वाला मोड SHARED है.

ऑडियो का फ़ॉर्मैट

स्ट्रीम से पास किए जाने वाले डेटा में, आम तौर पर इस्तेमाल होने वाले डिजिटल ऑडियो एट्रिब्यूट इस्तेमाल किए जाते हैं. इनके बारे में यहां बताया गया है:

  • सैंपल डेटा का फ़ॉर्मैट
  • चैनलों की संख्या (हर फ़्रेम के हिसाब से सैंपल)
  • सैंपल रेट

Aऑडियो इन सैंपल फ़ॉर्मैट की अनुमति देता है:

ऑडियो_फ़ॉर्मैट_नहीं C डेटा टाइप नोट
AAUDIO_FORMAT_PCM_I16 पूर्णांक16_t सामान्य 16-बिट सैंपल, Q0.15 फ़ॉर्मैट
AAUDIO_FORMAT_PCM_FLOAT फ़्लोट -1.0 से +1.0
AAUDIO_FORMAT_PCM_I24_PACKED 3 के ग्रुप में uint8_t पैक किए गए 24-बिट सैंपल, Q0.23 फ़ॉर्मैट
AAUDIO_FORMAT_PCM_I32 पूर्णांक32_t सामान्य 32-बिट सैंपल, Q0.31 फ़ॉर्मैट
ऑडियो_फ़ॉर्मैट_IEC61937 uint8_t एचडीएमआई या S/PDIF पासथ्रू के लिए IEC61937 में रैप किया गया कंप्रेस किया गया ऑडियो

अगर आपने किसी सैंपल फ़ॉर्मैट का अनुरोध किया है, तो स्ट्रीम उस फ़ॉर्मैट का इस्तेमाल करेगी, भले ही डिवाइस के लिए यह फ़ॉर्मैट सही न हो. अगर आपने सैंपल के तौर पर कोई फ़ॉर्मैट नहीं चुना है, तो Aऑडियो सबसे सही फ़ॉर्मैट को चुनेगा. स्ट्रीम खुलने के बाद, आपको डेटा के सैंपल के लिए क्वेरी करनी होगी. इसके बाद ज़रूरत के मुताबिक डेटा बदलें, जैसा कि इस उदाहरण में है:

aaudio_format_t dataFormat = AAudioStream_getDataFormat(stream);
//... later
if (dataFormat == AAUDIO_FORMAT_PCM_I16) {
     convertFloatToPcm16(...)
}

ऑडियो स्ट्रीम बनाई जा रही है

Aऑडियो लाइब्रेरी, बिल्डर डिज़ाइन पैटर्न के हिसाब से बनाई जाती है और AAudioStreamBuilder होती है.

  1. कोई A AudioStreamBuilder बनाएं:

    AAudioStreamBuilder *builder;
    aaudio_result_t result = AAudio_createStreamBuilder(&builder);
    

  2. स्ट्रीम पैरामीटर से जुड़े बिल्डर फ़ंक्शन का इस्तेमाल करके, बिल्डर में ऑडियो स्ट्रीम कॉन्फ़िगरेशन सेट करें. ये वैकल्पिक सेट फ़ंक्शन उपलब्ध हैं:

    AAudioStreamBuilder_setDeviceId(builder, deviceId);
    AAudioStreamBuilder_setDirection(builder, direction);
    AAudioStreamBuilder_setSharingMode(builder, mode);
    AAudioStreamBuilder_setSampleRate(builder, sampleRate);
    AAudioStreamBuilder_setChannelCount(builder, channelCount);
    AAudioStreamBuilder_setFormat(builder, format);
    AAudioStreamBuilder_setBufferCapacityInFrames(builder, frames);
    

    ध्यान दें कि इन तरीकों से गड़बड़ियों की जानकारी नहीं मिलती है. जैसे, कोई तय नहीं किया गया स्थिरांक या वैल्यू, रेंज से बाहर है.

    अगर deviceId की जानकारी नहीं दी जाती है, तो प्राइमरी आउटपुट डिवाइस डिफ़ॉल्ट तौर पर सेट हो जाता है. अगर आपने स्ट्रीम की दिशा की जानकारी नहीं दी है, तो डिफ़ॉल्ट तौर पर आउटपुट स्ट्रीम डिफ़ॉल्ट तौर पर सेट हो जाएगी. अन्य सभी पैरामीटर के लिए, आप स्पष्ट रूप से मान सेट कर सकते हैं या सिस्टम को पैरामीटर या सेटिंग के बारे में जानकारी न देकर, सबसे अच्छी वैल्यू असाइन करने की अनुमति दें AAUDIO_UNSPECIFIED के लिए.

    सुरक्षित रहने के लिए, ऑडियो स्ट्रीम बनाने के बाद उसकी स्थिति देखें. इस बारे में नीचे चौथे चरण में बताया गया है.

  3. A AudioStreamBuilder को कॉन्फ़िगर किया जा सकता है, इसका इस्तेमाल करके स्ट्रीम बनाएं:

    AAudioStream *stream;
    result = AAudioStreamBuilder_openStream(builder, &stream);
    

  4. स्ट्रीम बनाने के बाद, उसके कॉन्फ़िगरेशन की पुष्टि करें. अगर आपने तय किया है कि सैंपल फ़ॉर्मैट, सैंपल रेट या हर फ़्रेम के सैंपल पर लागू होने वाले सैंपल. अगर आपने शेयरिंग मोड या बफ़र की क्षमता के बारे में बताया है, तो ये बदल सकती हैं स्ट्रीम के ऑडियो डिवाइस की क्षमताओं और वह Android डिवाइस जिस पर वह चल रहा है. अच्छे सुरक्षा के लिए तो आपको स्ट्रीम का इस्तेमाल करने से पहले उसकी कॉन्फ़िगरेशन की जांच करनी चाहिए. स्ट्रीम सेटिंग को फिर से हासिल करने के लिए कई फ़ंक्शन हैं, जो बिल्डर सेटिंग:

    AAudioStreamBuilder_setDeviceId() AAudioStream_getDeviceId()
    AAudioStreamBuilder_setDirection() AAudioStream_getDirection()
    AAudioStreamBuilder_setSharingMode() AAudioStream_getSharingMode()
    AAudioStreamBuilder_setSampleRate() AAudioStream_getSampleRate()
    AAudioStreamBuilder_setChannelCount() AAudioStream_getChannelCount()
    AAudioStreamBuilder_setFormat() AAudioStream_getFormat()
    AAudioStreamBuilder_setBufferCapacityInFrames() AAudioStream_getBufferCapacityInFrames()

  5. इस बिल्डर को सेव करें और आने वाले समय में इसका फिर से इस्तेमाल करके, ज़्यादा स्ट्रीम करें. हालांकि, अगर आप अब इसका इस्तेमाल नहीं करना चाहते हैं, तो आपको इसे मिटा देना चाहिए.

    AAudioStreamBuilder_delete(builder);
    

ऑडियो स्ट्रीम का इस्तेमाल करना

स्टेट ट्रांज़िशन

ऑडियो स्ट्रीम आम तौर पर, पांच में से किसी एक स्थिर स्थिति में होती है (गड़बड़ी की स्थिति, 'डिसकनेक्ट है' के बारे में इस सेक्शन के आखिर में बताया गया है):

  • खोलें
  • शुरू किया गया
  • रोकी गई
  • शर्म से लाल चेहरा
  • बंद की गई

डेटा किसी स्ट्रीम में सिर्फ़ तब ही फ़्लो करता है, जब स्ट्रीम 'शुरू करें' स्थिति में हो. यहां की यात्रा पर हूं स्ट्रीम को एक से दूसरी स्थिति में ले जाने के लिए, किसी राज्य का अनुरोध करने वाले फ़ंक्शन में से किसी एक का इस्तेमाल करें ट्रांज़िशन:

aaudio_result_t result;
result = AAudioStream_requestStart(stream);
result = AAudioStream_requestStop(stream);
result = AAudioStream_requestPause(stream);
result = AAudioStream_requestFlush(stream);

ध्यान दें कि आउटपुट स्ट्रीम को रोकने या फ़्लश करने का ही अनुरोध किया जा सकता है:

ये फ़ंक्शन एसिंक्रोनस होते हैं और इनके स्टेटस में कोई बदलाव नहीं होता तुरंत. जब आप राज्य में बदलाव का अनुरोध करते है, तो स्ट्रीम ये उनकी अस्थायी स्थितियां होती हैं:

  • शुरू हो रहा है
  • रोका जा रहा है
  • फ़्लशिंग
  • बंद किया जा रहा है
  • आखिरी हिस्सा

नीचे दिया गया चित्र, स्थिर स्थितियों को गोल आयतों के रूप में और क्षणिक स्थितियों को बिंदु वाले आयतों के रूप में दिखाता है. यह प्रॉम्प्ट नहीं दिख रहा है, लेकिन close() को किसी भी राज्य से कॉल किया जा सकता है

Aऑडियो लाइफ़साइकल

ऑडियो में हुए बदलावों की सूचना देने के लिए, ऑडियो कॉलबैक नहीं देता. एक खास फ़ंक्शन, स्टेटस बदलने के लिए इंतज़ार करने के लिए, AAudioStream_waitForStateChange(stream, inputState, nextState, timeout) का इस्तेमाल किया जा सकता है.

फ़ंक्शन, स्थिति में होने वाले बदलाव का अपने-आप पता नहीं लगाता और किसी स्थिति के लिए चुना गया है. यह मौजूदा स्थिति आने तक इंतज़ार करता है inputState से अंतर है, जिसे आप तय करते हैं.

उदाहरण के लिए, वीडियो रोकने का अनुरोध करने के बाद, स्ट्रीम को तुरंत क्षणिक स्थिति रुकना और कुछ समय बाद रुकी हुई स्थिति में पहुंचना - हालांकि इसकी कोई गारंटी नहीं है कि इसके होने की कोई गारंटी नहीं है. आप 'रोका गया' स्टेटस का इंतज़ार नहीं कर सकते. किसी भी स्थिति का इंतज़ार करने के लिए, waitForStateChange() का इस्तेमाल करें रोकने के अलावा. इसका तरीका यहां बताया गया है:

aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
aaudio_stream_state_t nextState = AAUDIO_STREAM_STATE_UNINITIALIZED;
int64_t timeoutNanos = 100 * AAUDIO_NANOS_PER_MILLISECOND;
result = AAudioStream_requestPause(stream);
result = AAudioStream_waitForStateChange(stream, inputState, &nextState, timeoutNanos);

अगर स्ट्रीम की स्थिति रुक नहीं रही है (inputState, जिसे हमने माना था कि मौजूदा स्थिति), तो फ़ंक्शन तुरंत वापस आ जाता है. अगर ऐसा नहीं है, तो रोक तब तक ब्लॉक करता है, जब तक स्थिति 'रोकना' बंद न हो जाए या टाइम आउट खत्म न हो जाए. जब फ़ंक्शन रिटर्न करता है, तो पैरामीटर nextState स्ट्रीम.

आप इसी तकनीक का इस्तेमाल, अनुरोध को शुरू करने, बंद करने या फ़्लश करने के बाद भी कर सकते हैं, इसका इस्तेमाल, ऐसी अस्थायी स्थिति का इस्तेमाल करता है जिसेinputState के तौर पर इस्तेमाल किया जा रहा हो. कॉल न करें स्ट्रीम करने के बाद, AAudioStream_close() पर कॉल करने के बाद waitForStateChange() इसे बंद करते ही मिटा दिया जाएगा. और AAudioStream_close() को कॉल न करें जबकि waitForStateChange() किसी अन्य थ्रेड में चल रहा है.

किसी ऑडियो स्ट्रीम में पढ़ना और लिखना

स्ट्रीम शुरू होने के बाद, उसमें डेटा को प्रोसेस करने के दो तरीके हैं:

ब्लॉक किए गए रीड या राइटिंग के लिए, तय की गई संख्या में फ़्रेम की संख्या ट्रांसफ़र करें. इसके लिए, timeNanos को शून्य से ज़्यादा पर सेट करें. ब्लॉक न करने वाले कॉल के लिए, timeNanos को शून्य पर सेट करें. इस मामले में नतीजा, ट्रांसफ़र किए गए फ़्रेम की असल संख्या होती है.

इनपुट पढ़ते समय, आपको इसकी सही संख्या की पुष्टि करनी चाहिए फ़्रेम पढ़े गए. अगर ऐसा नहीं होता है, तो बफ़र में ऐसा अज्ञात डेटा हो सकता है जिसकी वजह से ऑडियो ग्लिच. बफ़र को शून्यों से पैड करके साइलेंट ड्रॉपआउट:

aaudio_result_t result =
    AAudioStream_read(stream, audioData, numFrames, timeout);
if (result < 0) {
  // Error!
}
if (result != numFrames) {
  // pad the buffer with zeros
  memset(static_cast<sample_type*>(audioData) + result * samplesPerFrame, 0,
      sizeof(sample_type) * (numFrames - result) * samplesPerFrame);
}

स्ट्रीम शुरू करने से पहले, स्ट्रीम के बफ़र को प्राइम किया जा सकता है. इसके लिए, डेटा लिखें या स्ट्रीम में आवाज़ बंद करें. यह कार्रवाई, ब्लॉक न करने वाले कॉल के दौरान की जानी चाहिए. इस कॉल में timeNanos की वैल्यू शून्य पर सेट की जानी चाहिए.

बफ़र का डेटा, AAudioStream_getDataFormat() से मिले डेटा फ़ॉर्मैट से मेल खाना चाहिए.

ऑडियो स्ट्रीम बंद करना

स्ट्रीम का इस्तेमाल पूरा होने के बाद, इसे बंद कर दें:

AAudioStream_close(stream);

किसी स्ट्रीम को बंद करने के बाद, उसे किसी भी ऑडियो स्ट्रीम-आधारित फ़ंक्शन के साथ इस्तेमाल नहीं किया जा सकता.

डिसकनेक्ट की गई ऑडियो स्ट्रीम

इनमें से कोई भी घटना होने पर, ऑडियो स्ट्रीम कभी भी डिसकनेक्ट हो सकती है:

  • डिवाइस से जुड़ा ऑडियो डिवाइस अब कनेक्ट नहीं है. उदाहरण के लिए, हेडफ़ोन के अनप्लग होने पर ऐसा किया जा सकता है.
  • सिस्टम में कोई गड़बड़ी होती है.
  • ऑडियो डिवाइस, अब मुख्य ऑडियो डिवाइस नहीं है.

जब कोई स्ट्रीम डिसकनेक्ट होती है, तो उसकी स्थिति "डिसकनेक्ट है" के तौर पर दिखती है साथ ही, AAudioStream_write() या अन्य फ़ंक्शन लागू करने की कोशिश करने पर, आपको गड़बड़ी का मैसेज दिखेगा. डिसकनेक्ट की गई स्ट्रीम को हमेशा रोकना और बंद करना चाहिए, चाहे गड़बड़ी का कोड कोई भी हो.

अगर डेटा कॉलबैक (सीधे पढ़ने/लिखने के किसी एक तरीके के उलट) का इस्तेमाल किया जा रहा है तो स्ट्रीम डिसकनेक्ट होने पर आपको रिटर्न कोड नहीं मिलेगा. ऐसा होने पर सूचना पाने के लिए, AAudioStream_errorCallback लिखें फ़ंक्शन का इस्तेमाल कर सकते हैं और AAudioStreamBuilder_setErrorCallback().

अगर आपको किसी गड़बड़ी कॉलबैक थ्रेड में डिसकनेक्ट होने की सूचना मिलती है, तो बंद हो रहा है और बंद हो रहा है की स्ट्रीम किसी दूसरी थ्रेड से की जानी चाहिए. नहीं तो, आपके पास डेडलॉक हो सकता है.

ध्यान दें कि नई स्ट्रीम खोलने पर, उसकी सेटिंग अलग हो सकती हैं (उदाहरण के लिए,FramePerBurst):

void errorCallback(AAudioStream *stream,
                   void *userData,
                   aaudio_result_t error) {
    // Launch a new thread to handle the disconnect.
    std::thread myThread(my_error_thread_proc, stream, userData);
    myThread.detach(); // Don't wait for the thread to finish.
}

परफ़ॉर्मेंस ऑप्टिमाइज़ करना

किसी ऑडियो ऐप्लिकेशन की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, उसके अंदरूनी बफ़र को अडजस्ट करें. साथ ही, ज़्यादा प्राथमिकता वाले खास थ्रेड का इस्तेमाल करें.

इंतज़ार का समय कम करने के लिए बफ़र ट्यून करना

Aऑडियो, हर ऑडियो डिवाइस के लिए बनाए गए अंदरूनी बफ़र में और उससे बाहर डेटा पास करता है.

बफ़र की क्षमता, डेटा की कुल मात्रा होती है जो बफ़र में सेव हो सकती है. कॉल किया जा सकता है AAudioStreamBuilder_setBufferCapacityInFrames() क्षमता सेट करने के लिए. यह तरीका, डिवाइस की क्षमता के लिए तय की गई सीमा को तय करता है. इस्तेमाल की जाने वाली चीज़ें AAudioStream_getBufferCapacityInFrames() बफ़र की असल कपैसिटी की पुष्टि करें.

ऐप्लिकेशन को बफ़र की पूरी क्षमता का इस्तेमाल करने की ज़रूरत नहीं है. ऑडियो बफ़र को साइज़ में भरता है, जिसे सेट किया जा सकता है. बफ़र का साइज़, उसकी क्षमता से बड़ा नहीं हो सकता. हालांकि, यह अक्सर छोटा होता है. बफ़र साइज़ को कंट्रोल करके, यह तय किया जाता है कि इसे भरने के लिए कितने बर्स्ट की ज़रूरत होगी. इससे, इंतज़ार का समय भी कंट्रोल होता है. AAudioStreamBuilder_setBufferSizeInFrames() तरीके का इस्तेमाल करें और AAudioStreamBuilder_getBufferSizeInFrames() बफ़र साइज़ के साथ काम करता है.

जब कोई ऐप्लिकेशन ऑडियो को चलाता है, तो वह बफ़र में लिखता है और राइटिंग पूरा होने तक ब्लॉक करता है. ऑडियो अलग-अलग बर्स्ट में बफ़र से पढ़ता है. हर बर्स्ट में कई ऑडियो फ़्रेम होते हैं और यह आम तौर पर पढ़े जा रहे बफ़र के साइज़ से कम होता है. सिस्टम, बर्स्ट के साइज़ और रेट को कंट्रोल करता है. आम तौर पर, इन प्रॉपर्टी के हिसाब से ऑडियो डिवाइस की सर्किट का इस्तेमाल किया जाता है. हालांकि, बर्स्ट का साइज़ या बर्स्ट रेट में बदलाव नहीं किया जा सकता. हालांकि, इंटरनल बफ़र का साइज़, उसमें मौजूद बर्स्ट की संख्या के हिसाब से सेट किया जा सकता है. आम तौर पर, अगर आपके AAudioStream का बफ़र साइज़, रिपोर्ट किए गए बर्स्ट साइज़ के मल्टीपल है, तो वीडियो स्ट्रीम होने और उसके दिखने के समय का अंतर सबसे कम होगा.

      ऑडियो बफ़रिंग

बफ़र साइज़ को ऑप्टिमाइज़ करने का एक तरीका यह है कि आप बड़े बफ़र से शुरू करें और फिर इसे धीरे-धीरे तब तक कम करें, जब तक अंडररन न होने शुरू हो जाएं और फिर ऊपर की ओर खिसकाएं. इसके अलावा, छोटे बफ़र साइज़ से शुरुआत की जा सकती है. अगर इससे कम बफ़र होते हैं, तो बफ़र का साइज़ तब तक बढ़ाएं, जब तक आउटपुट पूरी तरह से साफ़ न हो जाए.

यह प्रोसेस बहुत जल्दी पूरी हो सकती है. ऐसा भी हो सकता है कि उपयोगकर्ता पहली बार साउंड बजाएं. हो सकता है कि आप बिना आवाज़ के शुरुआती बफ़र का साइज़ तय करना चाहें, ताकि उपयोगकर्ता को कोई भी ऑडियो ग्लिच न सुनाई दे. सिस्टम की परफ़ॉर्मेंस समय के साथ बदल सकती है. उदाहरण के लिए, उपयोगकर्ता फ़्लाइट मोड बंद कर सकता है. बफ़र ट्यूनिंग की प्रोसेस में बहुत कम ओवरहेड बढ़ते हैं, इसलिए आपका ऐप्लिकेशन जब तक ऐप्लिकेशन किसी स्ट्रीम में डेटा पढ़ता या लिखता है, तब तक लगातार इस कार्रवाई को किया जा सकता है.

यहां बफ़र ऑप्टिमाइज़ेशन लूप का उदाहरण दिया गया है:

int32_t previousUnderrunCount = 0;
int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
int32_t bufferSize = AAudioStream_getBufferSizeInFrames(stream);

int32_t bufferCapacity = AAudioStream_getBufferCapacityInFrames(stream);

while (go) {
    result = writeSomeData();
    if (result < 0) break;

    // Are we getting underruns?
    if (bufferSize < bufferCapacity) {
        int32_t underrunCount = AAudioStream_getXRunCount(stream);
        if (underrunCount > previousUnderrunCount) {
            previousUnderrunCount = underrunCount;
            // Try increasing the buffer size by one burst
            bufferSize += framesPerBurst;
            bufferSize = AAudioStream_setBufferSize(stream, bufferSize);
        }
    }
}

किसी इनपुट स्ट्रीम के बफ़र साइज़ को ऑप्टिमाइज़ करने के लिए, इस तकनीक का इस्तेमाल करने का कोई फ़ायदा नहीं है. इनपुट स्ट्रीम जितनी तेज़ी से हो सके उतनी तेज़ी से चलती हैं. इसलिए, कोशिश की जाती है कि यह जितने समय तक रहे बफ़र किए गए डेटा को कम से कम पर सेट करना और फिर ऐप्लिकेशन को पहले से खाली किए जाने पर उसे भरना.

ज़्यादा प्राथमिकता वाले कॉलबैक का इस्तेमाल करना

अगर आपका ऐप्लिकेशन किसी सामान्य थ्रेड से ऑडियो डेटा पढ़ता या लिखता है, तो हो सकता है कि वह पहले से उपलब्ध हो या समय के साथ सिग्नल में गड़बड़ी हो रही हो. इस वजह से, ऑडियो में गड़बड़ियां हो सकती हैं. बड़े बफ़र का इस्तेमाल करने से, हो सकता है कि इनकी वजह से आने वाली समस्याओं से बचा जा सके, लेकिन बड़े बफ़र का इस्तेमाल करने पर, ऑडियो में देरी भी ज़्यादा हो सकती है. जिन ऐप्लिकेशन के लोड होने में कम समय लगता है उनके लिए, ऑडियो स्ट्रीम आपके ऐप्लिकेशन में डेटा ट्रांसफ़र करने के लिए एसिंक्रोनस कॉलबैक फ़ंक्शन का इस्तेमाल कर सकती है. Aऑडियो, ज़्यादा प्राथमिकता वाले थ्रेड में कॉलबैक को एक्ज़ीक्यूट करता है जिसकी परफ़ॉर्मेंस बेहतर होती है.

कॉलबैक फ़ंक्शन का यह प्रोटोटाइप है:

typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames);

कॉलबैक रजिस्टर करने के लिए, स्ट्रीम बिल्डिंग का इस्तेमाल करें:

AAudioStreamBuilder_setDataCallback(builder, myCallback, myUserData);

सबसे सामान्य स्थिति में, स्ट्रीम समय-समय पर कॉलबैक फ़ंक्शन को अगले बर्स्ट के लिए डेटा हासिल कर सकता है.

कॉलबैक फ़ंक्शन को ऐसी स्ट्रीम पर रीड या राइट नहीं करना चाहिए ने शुरू किया. अगर कॉलबैक किसी इनपुट स्ट्रीम से जुड़ा है, तो आपका कोड प्रोसेस होना चाहिए ऑडियो डेटा बफ़र में दिया गया डेटा (तीसरे पक्ष के तर्क से मेल खाता है. अगर कॉलबैक किसी आउटपुट स्ट्रीम से जुड़ा है, तो आपका कोड डेटा को बफ़र में रखें.

उदाहरण के लिए, साइन वेव आउटपुट को लगातार जनरेट करने के लिए, कॉलबैक का इस्तेमाल किया जा सकता है इस तरह:

aaudio_data_callback_result_t myCallback(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames) {
    int64_t timeout = 0;

    // Write samples directly into the audioData array.
    generateSineWave(static_cast<float *>(audioData), numFrames);
    return AAUDIO_CALLABCK_RESULT_CONTINUE;
}

AAudio का इस्तेमाल करके एक से ज़्यादा स्ट्रीम प्रोसेस की जा सकती हैं. मास्टर के तौर पर एक स्ट्रीम का इस्तेमाल किया जा सकता है और उपयोगकर्ता डेटा में अन्य स्ट्रीम के लिए पॉइंटर पास करना. मास्टर स्ट्रीम के लिए कॉलबैक रजिस्टर करें. इसके बाद, दूसरी स्ट्रीम पर ब्लॉक न करने वाले I/O का इस्तेमाल करें. यहां दोतरफ़ा यात्रा के कॉलबैक का एक उदाहरण दिया गया है, जो आउटपुट स्ट्रीम में इनपुट स्ट्रीम पास करता है. मास्टर कॉलिंग स्ट्रीम एक आउटपुट स्ट्रीम है. उपयोगकर्ता के डेटा में इनपुट स्ट्रीम शामिल होती है.

कॉलबैक इनपुट स्ट्रीम से बिना रुकावट पढ़े जाने वाले डेटा को आउटपुट स्ट्रीम के बफ़र में डाल देता है:

aaudio_data_callback_result_t myCallback(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames) {
    AAudioStream *inputStream = (AAudioStream *) userData;
    int64_t timeout = 0;
    aaudio_result_t result =
        AAudioStream_read(inputStream, audioData, numFrames, timeout);

  if (result == numFrames)
      return AAUDIO_CALLABCK_RESULT_CONTINUE;
  if (result >= 0) {
      memset(static_cast<sample_type*>(audioData) + result * samplesPerFrame, 0,
          sizeof(sample_type) * (numFrames - result) * samplesPerFrame);
      return AAUDIO_CALLBACK_RESULT_CONTINUE;
  }
  return AAUDIO_CALLBACK_RESULT_STOP;
}

ध्यान दें कि इस उदाहरण में यह माना गया है कि इनपुट और आउटपुट स्ट्रीम में चैनल की संख्या, फ़ॉर्मैट, और सैंपल रेट बराबर है. ऐसा हो सकता है कि स्ट्रीम का फ़ॉर्मैट मेल न खाए. हालांकि, कोड का अनुवाद सही तरीके से हैंडल होने पर भी ऐसा हो सकता है.

परफ़ॉर्मेंस मोड सेट करना

हर AAudioStream का एक परफ़ॉर्मेंस मोड होता है, जो आपके ऐप्लिकेशन के काम करने के तरीके पर काफ़ी असर डालता है. इसके तीन मोड हैं:

  • AAUDIO_PERFORMANCE_MODE_NONE डिफ़ॉल्ट मोड है. यह ऐसी बेसिक स्ट्रीम का इस्तेमाल करता है जो इंतज़ार का समय और बिजली की बचत को संतुलित करती है.
  • AAUDIO_PERFORMANCE_MODE_LOW_LATENCY छोटे बफ़र का इस्तेमाल करता है और इंतज़ार का समय कम करने के लिए, ऑप्टिमाइज़ किया गया डेटा पाथ का इस्तेमाल करता है.
  • AAUDIO_PERFORMANCE_MODE_POWER_SAVING बड़े इंटरनल बफ़र और डेटा पाथ का इस्तेमाल करता है, जो बैटरी कम होने पर इंतज़ार का समय खत्म करता है.

setPerformanceMode() को कॉल करके, परफ़ॉर्मेंस मोड चुना जा सकता है, साथ ही, getPerformanceMode() को कॉल करके मौजूदा मोड के बारे में जानें.

अगर ऐप्लिकेशन में बिजली की बचत करने के बजाय, इंतज़ार का समय कम होना ज़्यादा ज़रूरी है, तो AAUDIO_PERFORMANCE_MODE_LOW_LATENCY का इस्तेमाल करें. यह उन ऐप्लिकेशन के लिए मददगार है जो बहुत इंटरैक्टिव होते हैं. जैसे, गेम या कीबोर्ड सिंथेसाइज़र.

अगर ऐप्लिकेशन में इंतज़ार का समय कम करने के बजाय, बैटरी सेव करना ज़्यादा ज़रूरी है, तो AAUDIO_PERFORMANCE_MODE_POWER_SAVING का इस्तेमाल करें. ऐसा उन ऐप्लिकेशन के लिए आम तौर पर होता है जो पहले जनरेट किए गए संगीत को चलाते हैं, जैसे कि स्ट्रीमिंग ऑडियो या एमआईडीआई फ़ाइल प्लेयर.

Aऑडियो के मौजूदा वर्शन में, इंतज़ार का समय कम से कम रखने के लिए, आपको ज़्यादा प्राथमिकता वाले कॉलबैक के साथ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY परफ़ॉर्मेंस मोड का इस्तेमाल करना होगा. इस उदाहरण का पालन करें:

// Create a stream builder
AAudioStreamBuilder *streamBuilder;
AAudio_createStreamBuilder(&streamBuilder);
AAudioStreamBuilder_setDataCallback(streamBuilder, dataCallback, nullptr);
AAudioStreamBuilder_setPerformanceMode(streamBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

// Use it to create the stream
AAudioStream *stream;
AAudioStreamBuilder_openStream(streamBuilder, &stream);

थ्रेड की सुरक्षा

AAudio API पूरी तरह से थ्रेड सुरक्षित नहीं है. एक बार में एक से ज़्यादा थ्रेड से, कुछ ऑडियो फ़ंक्शन को एक साथ कॉल नहीं किया जा सकता. ऐसा इसलिए होता है, क्योंकि Aऑडियो में म्यूटेक्स का इस्तेमाल करने से बचा जा सकता है. इससे थ्रेड पहले से ही छूट और तकनीकी समस्याएं आ सकती हैं.

सुरक्षित रहने के लिए, AAudioStream_waitForStateChange() को कॉल न करें, न ही दो अलग-अलग थ्रेड से एक ही स्ट्रीम में लिखें और न ही उसे पढ़ें. इसी तरह, किसी दूसरी थ्रेड में स्ट्रीम को पढ़ते या लिखते समय, उसकी किसी स्ट्रीम को बंद न करें.

ऐसे कॉल जो स्ट्रीम की सेटिंग पर वापस आते हैं, जैसे कि AAudioStream_getSampleRate() और AAudioStream_getChannelCount(), थ्रेड सुरक्षित हैं.

इन कॉल में भी थ्रेड को सुरक्षित रखा जा सकता है:

  • AAudio_convert*ToText()
  • AAudio_createStreamBuilder()
  • AAudioStream_getTimestamp() को छोड़कर AAudioStream_get*()

पहले से मालूम समस्याएं

  • Android O DP2 रिलीज़ में तेज़ ट्रैक का इस्तेमाल नहीं होता है. इसलिए, Write() को ब्लॉक करने के लिए, ऑडियो के इंतज़ार का समय ज़्यादा होता है. इंतज़ार का समय कम करने के लिए, कॉलबैक का इस्तेमाल करें.

अन्य संसाधन

ज़्यादा जानकारी के लिए, यहां दिए गए संसाधनों का फ़ायदा लें:

API संदर्भ

कोड लैब

वीडियो