рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ OpenAL рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП Android NDK рдореВрд▓ рдмрд╛рддреЗрдВ

рд╢реБрдн рджрд┐рди, рдкреНрд░рд┐рдп Habrausers!

рд╣рд╛рд▓ рд╣реА рдореЗрдВ, рдореИрдВ рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рд▓рд┐рдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЧреЗрдо рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдРрд╕рд╛ рд╣реБрдЖ рдХрд┐ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдПрдВрдбреНрд░реЙрдЗрдб рдПрдирдбреАрдХреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдкрдбрд╝рд╛ред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдПрдХ рд▓реЗрдЦ рдореЗрдВ рдореВрд▓ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рд╕рднреА рдХрдард┐рдирд╛рдЗрдпреЛрдВ рдФрд░ рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ, рдореИрдВрдиреЗ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ ndk рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдкрд░рд┐рдЪрдп рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред
рдФрд░ рд▓реЗрдЦ рдХреЛ рди рдХреЗрд╡рд▓ рд╢реБрд░реБрдЖрддреА рдХреЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдк рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдУрдВрдЧрд▓ рдФрд░ рдбрдмреНрд▓реНрдпреВрдПрд╡реА, рдУрдЬреАрдЬреА рдкреНрд░рд╛рд░реВрдкреЛрдВ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╛рдо рдХрд┐рдпрд╛ рдЬрд╛рдПред



рдкрд░рд┐рдЪрдп


рдпрд╣ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреА рд╕реНрдерд╛рдкрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╣реБрдд рдХреБрдЫ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд╛рдпрдХ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИред рднрд▓реЗ рд╣реА рдЖрдк рдЬрд┐рд╕ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╡рд┐рдХрд╛рд╕ рдХрд░ рд░рд╣реЗ рд╣реЛрдВ (рдЧреНрд░рд╣рдг, рдЗрдВрдЯреЗрд▓реАрдЬ рдЖрдИрдбрд┐рдпрд╛, рдЖрджрд┐), рд╕реЗрдЯрдЕрдк рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред
  1. Android NDK рд╣реА ред
  2. WIn рдХреЗ рддрд╣рдд рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╕рд╛рдЗрдЧрд╡рд┐рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ ред
  3. рдкреНрд▓рдЧрдЗрдиреНрд╕, рдЙрд╕реА рдЧреНрд░рд╣рдг рдХреЗ рд▓рд┐рдП: рд╕реАрдбреАрдЯреА ред

рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдкрдХреЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА ADT, JDK рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╣рдореЗрдВ рдПрдирдбреАрдХреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ?



рдЬрд╛рд╡рд╛ рд╕реЗ C ++ рдХреЛрдб рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ


рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╕рдм рдХреБрдЫ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдореБрдЦреНрдп рдЪрд░рдг:
  1. C ++ рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓ рдмрдирд╛рдирд╛ рдФрд░ рдПрдХреНрд╕рдкреЛрд░реНрдЯ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ред
  2. .Mk рдлрд╛рдЗрд▓реЗрдВ рдмрдирд╛рдирд╛ред
  3. рдкреБрд╕реНрддрдХрд╛рд▓рдп рдкреАрдврд╝реАред
  4. рдЬрд╛рд╡рд╛ рдореЗрдВ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрдиреЗрдХреНрдЯ рдХрд░рдирд╛ред



Makefiles (.mk) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореИрдВ рдкреЗрдВрдЯ рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ред рдЖрдк рдЙрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╣рд╛рдВ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рд╣рдм рдкрд░ BubaVV рд╕реЗ .mk рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рд▓реЗрдЦ рд╣реИ ред

рдЖрдк рдпрд╣рд╛рдБ ndk рд╕реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред

C ++ рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдирд╛

рдирд┐рд░реНрдпрд╛рдд рдХреЗ рд▓рд┐рдП рддрд░реАрдХреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдЬрд╛рд╡рд╛ рд╕реЗ рдХрд╣реЗрдВрдЧреЗред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рдЬрдм рдЖрд╡реЗрджрди рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо рдУрдкрди рдореЗрдВ рд╕рдВрдЧреАрдд рд▓реЛрдб рдХрд░реЗрдВрдЧреЗред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рд╡рд┐рдзрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ:
JNIEXPORT void JNICALL Java_ru_suvitruf_androidndk_tutorial4_MainActivity_loadAudio(JNIEnv *pEnv, jobject pThis, jobject pNativeCallListener, jobject assetManager); 


рдореИрдВ рдпрд╣ рд╕рдм рдХрд▓рдо рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЬреЗрд╡рд╣ рдХреА рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкреАрдврд╝реА рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИред

рдлрд┐рд░ рд╣рдореЗрдВ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рдЙрд╕ рдкрд░ рдФрд░ рдмрд╛рдж рдореЗрдВред
рдирд╛рдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛
рдпрд╣ рддрд░реАрдХреЛрдВ рдХреЗ рдирд╛рдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рдХрд╣рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИред Java_ рдПрдХ рдЖрд╡рд╢реНрдпрдХ рдЙрдкрд╕рд░реНрдЧ рд╣реИред ru_suvitruf_androidndk_tutorial4 , рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ ru.suvitruf.androidndk.tutorial4 рдкреИрдХреЗрдЬ рд╣реИ, рдФрд░ рддрдм рдХреНрд▓рд╛рд╕ рдФрд░ рдореЗрдердб рдХрд╛ рдирд╛рдо рдЬрд╛рд╡рд╛ рдХреА рддрд░рдл рд╣реЛрддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ JNIEnv * рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╣реИ - рдЬрд╛рд╡рд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕, рдЗрд╕рдХреЗ рд╕рд╛рде рдЖрдк рдЬрд╛рд╡рд╛ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд╛рд╡рд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рджреВрд╕рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдЬреЙрдмрдЬреЗрдХреНрдЯ рдпрд╛ jclass рд╣реИ , рдпрд╣ рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╡рд┐рдзрд┐ рд╕реНрдерд┐рд░ рд╣реИред рдпрджрд┐ рд╡рд┐рдзрд┐ рд╕реНрдерд┐рд░ рд╣реИ, рддреЛ рддрд░реНрдХ рдЯрд╛рдЗрдк jclass (рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рд╕рдВрджрд░реНрдн рдЬрд┐рд╕рдореЗрдВ рд╡рд┐рдзрд┐ рдШреЛрд╖рд┐рдд рдХреА рдЧрдИ рд╣реИ) рдХрд╛ рд╣реЛрдЧрд╛, рдпрджрд┐ рд╕реНрдерд┐рд░ рдирд╣реАрдВ рд╣реИ - jobject - рдЙрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рд╕рдВрджрд░реНрдн рдЬрд┐рд╕ рдкрд░ рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ред


рдЬрд╛рд╡рд╛ рдореЗрдВ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрдиреЗрдХреНрд╢рди

рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЛ рдЗрд╕реЗ рдЬрд╛рд╡рд╛ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
 static { System.loadLibrary("AndroidNDK"); } 


рдФрд░ C ++ рдХреЛрдб рдХреЗ рд╕рдорд╛рди рдирд╛рдо рд╡рд╛рд▓реА рд╡рд┐рдзрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:
 //  native public void loadAudio(NativeCalls nativeCallListener, AssetManager mng); 


рдЗрд╕ рддрд░рд╣ рдХреЙрд▓ рдХрд░реЗрдВ:
 loadAudio(activity, activity.getResources().getAssets()); 


C ++ рд╕реЗ рдЬрд╛рд╡рд╛ рдХреЙрд▓


рдереЛрдбрд╝рд╛ рдФрд░ рдЬрдЯрд┐рд▓, рд▓реЗрдХрд┐рди рдЗрддрдирд╛ рдбрд░рд╛рд╡рдирд╛ рдирд╣реАрдВред рд╣рдореЗрдВ рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП:
  1. рдХреНрд▓рд╛рд╕ рд╡рд┐рдзрд┐ (рдЬрд╛рд╡рд╛ рдореЗрдВ) рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ рдЬрд┐рд╕реЗ рд╣рдо рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
  2. рд╡рд╛рдВрдЫрд┐рдд рд╡рд░реНрдЧ (рд╕реА ++ рдореЗрдВ) рдХрд╛ рд╡рд┐рд╡рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред
  3. рд╡рд┐рдзрд┐ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВред
  4. рд╡рд┐рдзрд┐ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ (рд▓рд┐рдВрдХ) рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред
  5. рдЗрдЪреНрдЫрд┐рдд рд╡рд╕реНрддреБ рдкрд░ рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рдУред


рдмреЗрд╢рдХ, рдЖрдк рдмрд╕ рдХрдХреНрд╖рд╛ рдХреА рд╡рд┐рдзрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрдВрдЯрд░рдлреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИред рдпрджрд┐ рд╣рдореЗрдВ рджреВрд╕рд░реА рдХрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╣реИ рддреЛ рд╣рдореЗрдВ рдореВрд▓ рдХреЛрдб рдирд╣реАрдВ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ред

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛рдПрдБ:
 public interface NativeCalls { public void sendLog(String result); } 


CalledFromWrongThreadException рдФрд░ рдЙрдЪрд┐рдд рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЕрд░реЗ рдпреЗ рдмрд╣рддрд╛ рд╣реИред рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдЖрдк рдХрд┐рд╕реА рдЕрдиреНрдп рд╕реНрдЯреНрд░реАрдо рд╕реЗ рджреГрд╢реНрдп рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рдЗрд╕рд▓рд┐рдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╕рдВрдкреВрд░реНрдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╣реЛрдЧрд╛:
 protected Handler handler = new Handler() { @Override public void handleMessage(Message msg) { showResult(msg.getData().getString("result")); } }; public void showResult(String result){ ((TextView) findViewById(R.id.log)). setText(((TextView) findViewById(R.id.log)).getText()+result+"\n"); } //    @Override public void sendLog(String result){ Message msg = new Message(); Bundle data = new Bundle(); data.putString("result", result); msg.setData(data); handler.sendMessage(msg); } 



рдереНрд░реЗрдбреНрд╕ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдПрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрд╡реЗрджрди рд╢реБрд░реВ рдХрд░рддреЗ рд╕рдордп, рд╣рдо рд▓реЛрдбрд┐рдВрдЧ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдереНрд░реЗрдб рдмрдирд╛рдПрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдкреНрд░рд╢реНрди рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИред

рдирд┐рдореНрди рд╡рд░реНрдЧ рдореВрд▓ C ++ рдХреЛрдб рдореЗрдВ рдЬрд╛рд╡рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрдЧрд╛:
NativeCallListener
 class NativeCallListener { public: NativeCallListener(JNIEnv* pJniEnv, jobject pWrapperInstance); NativeCallListener() {} //  //   Java  void sendLog(jobject log); //   void destroy(); ~NativeCallListener(){ } void loadAudio(); //void play(); //void playOGG(); ALCdevice* device; ALCcontext* context; private: JNIEnv* getJniEnv(); //   jmethodID sendLogID; //   jobject mObjectRef; JavaVM* mJVM; ALuint soundWAV; ALuint soundOGG; void load(); void clean(); }; 


рдЕрдм рдЖрдк рд▓реЛрдбрдПрдбрд┐рдпреЛ рд╡рд┐рдзрд┐ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рджрд┐рдЦрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рд╢реАрд░реНрд╖рдХ рд▓реЗрдЦ рдХреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ рдореЗрдВ рдерд╛ред
 JNIEXPORT void JNICALL Java_ru_suvitruf_androidndk_tutorial4_MainActivity_loadAudio(JNIEnv *pEnv, jobject pThis, jobject pNativeCallListener, jobject assetManager) { listener = NativeCallListener(pEnv, pNativeCallListener); mgr = AAssetManager_fromJava(pEnv, assetManager); listener.loadAudio(); } 


рдХреНрд▓рд╛рд╕ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ, рд╣рдо рдХреНрд▓рд╛рд╕ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░ рдХреЛ рд╕реЗрд╡ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХреА рд╡рд┐рдзрд┐ рдХрд╛ рд╕рдВрджрд░реНрдн рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ:
 NativeCallListener::NativeCallListener(JNIEnv* pJniEnv, jobject pWrappedInstance) { pJniEnv->GetJavaVM(&mJVM); mObjectRef = pJniEnv->NewGlobalRef(pWrappedInstance); jclass cl = pJniEnv->GetObjectClass(pWrappedInstance); // ,       Java sendLogID = pJniEnv->GetMethodID(cl, "sendLog", "(Ljava/lang/String;)V"); } 


рдЕрдм рд╣рдо рдЬрд╛рд╡рд╛ рд╡рд┐рдзрд┐ рдХреЛ рд▓рд┐рдЦрдХрд░ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
 void NativeCallListener::sendLog(jobject log) { JNIEnv* jniEnv = getJniEnv(); jniEnv->CallIntMethod(mObjectRef, sendLogID, log); } 


AAssetManager


рдкрд╣рд▓реЗ, рдУрдкрди рд╕реЛрд░реНрд╕ рд▓рд┐рдмрдЬреАрдк рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рдерд╛ред
рдПрдкреАрдЖрдИ рдХреЗ рд╕рдВрд╕реНрдХрд░рдг 2.3 рдХреЗ рд╕рд╛рде, рдПрдВрдбреНрд░реЙрдЗрдб рдПрдирдбреАрдХреЗ рдХреЗ рдкрд╛рд╕ рд╕реА ++ рдХреЛрдб рд╕реЗ рд╕реАрдзреЗ рд╕рдВрдкрддреНрддрд┐ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╣рд╛рди рд╡рд░реНрдЧ рд╣реИред
рддрд░реАрдХреЗ stdio.h рд╕реЗ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рд╕рдорд╛рди рд╣реИрдВред AAssetManager_open рдмрдЬрд╛рдп fopen, AAsset_read рдмрдЬрд╛рдп fread, AAsset_close рдмрдЬрд╛рдп fcloseред

рдореИрдВрдиреЗ рдЙрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рд░реИрдкрд░ рд▓рд┐рдЦрд╛ред рдореИрдВ рдпрд╣рд╛рдВ рдХреЛрдб рдирд╣реАрдВ рдбрд╛рд▓реВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рдХрд╛рдо рд╕рд╛рдорд╛рдиреНрдп рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╕рд╛рде рд╣реА рд╣реЛрддрд╛ рд╣реИред

рдУрдкрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реЗрдВ


рд▓реЗрдЦ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рдлреА рдмрдбрд╝рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рд╣рд┐рд╕реНрд╕рд╛ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреНрд╖рдорд╛ рдХрд░реЗрдВ ...

рдЯреНрд░реЗрдирд┐рдВрдЧ

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ OpenAL рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ WAV рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдЕрднреА рднреА OGG рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдУрдЬреАрдЬреА рдХреЛ рдПрдХ рдЯреНрд░реЗрдорд░ рдбрд┐рдХреЛрдбрд░ рдХреА рдЬрд░реВрд░рдд рд╣реЛрддреА рд╣реИред

рдзреНрд╡рдирд┐ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рд░реИрдкрд░ рд▓рд┐рдЦреЗред рдпрд╣рд╛рдВ рд╕рднреА рдХреЛрдб рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдореИрдВ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк, рдЕрд░реНрдерд╛рддреН рдбрд╛рдЙрдирд▓реЛрдб рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░реВрдВрдЧрд╛ред

Wav рдлрд╝рд╛рдЗрд▓ рдкрдврд╝реЗрдВ

рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рд╣реЗрдбрд░ рдХреЗ рд▓рд┐рдП рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
BasicWAVEHeader
 typedef struct { char riff[4];//'RIFF' unsigned int riffSize; char wave[4];//'WAVE' char fmt[4];//'fmt ' unsigned int fmtSize; unsigned short format; unsigned short channels; unsigned int samplesPerSec; unsigned int bytesPerSec; unsigned short blockAlign; unsigned short bitsPerSample; char data[4];//'data' unsigned int dataSize; }BasicWAVEHeader; 



рдЕрдм рд╣рдо рдкрдврд╝рддреЗ рд╣реИрдВ:
 void OALWav::load(AAssetManager *mgr, const char* filename){ this->filename = filename; this->data = 0; //  this->data = this->readWAVFull(mgr, &header); //  getFormat(); // OpenAL  createBufferFromWave(data); source = 0; alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); } 


readWAVFull
 char* OALWav::readWAVFull(AAssetManager *mgr, BasicWAVEHeader* header){ char* buffer = 0; AAssetFile f = AAssetFile(mgr, filename); if (f.null()) { LOGE("no file %s in readWAV",filename); return 0; } int res = f.read(header,sizeof(BasicWAVEHeader),1); if(res){ if (!( //    . //   ,    . //          =/ memcmp("RIFF",header->riff,4) || memcmp("WAVE",header->wave,4) || memcmp("fmt ",header->fmt,4) || memcmp("data",header->data,4) )){ buffer = (char*)malloc(header->dataSize); if (buffer){ if(f.read(buffer,header->dataSize,1)){ f.close(); return buffer; } free(buffer); } } } f.close(); return 0; } 


WAV рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдХрд╣рд╛ рдЬрд╛рдирд╛ рд╣реИред рдХрднреА-рдХрднреА, рдкреАрд╕реА рдкрд░ рдлрд╝рд╛рдЗрд▓ рдареАрдХ рд╕реБрдирд╛рдИ рджреЗрддреА рд╣реИ, рд▓реЗрдХрд┐рди OpenAL рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛрддреА рд╣реИрдВред рдпрд╣ рд╣реЗрдбрд░ рдЯреВрдЯреЗ рд╣реЛрдиреЗ рдХрд╛ рдПрдХ рдкрд░рд┐рдгрд╛рдо рд╣реИред рдореИрдВ рдмрд╣реБрдд рд╕реЗ рдХрдиреНрд╡рд░реНрдЯрд░реНрд╕ рд╕реЗ рдорд┐рд▓рд╛, рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рд╣реЗрдбрд░реНрд╕ (рдЙрдирдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЛрдЧреЛ) рдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рдХреА рдмрдХрд╡рд╛рд╕ рд▓рд┐рдЦреА, рдЖрдорддреМрд░ рдкрд░ рдбреЗрдЯрд╛рд╕рд╛рдЗрдЬрд╝ рдореЗрдВ ред рддреЛ рдпрд╣ рдХрд╛рдо рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкреАрд╕реА рдкрд░ рдЦреЗрд▓рддрд╛ рд╣реИ?
рдбреЗрдЯрд╛ рдбреЗрдЯрд╛ рдХреЛ рд╣реЗрдбрд░ рдФрд░ рдЙрд╕рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рдмрд╛рдж рд╕реНрд╡рдпрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдпрджрд┐ рдЗрд╕ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдХреБрдЫ рдЧрдбрд╝рдмрдбрд╝ рд╣реИ, рддреЛ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛрдВрдЧреАред рдЖрдк рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорд╛рдереЗ рдореЗрдВ рдЖрдХрд╛рд░ рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдбреЗрдЯрд╛ рдХрд╛ рдЖрдХрд╛рд░ = рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЖрдХрд╛рд░ - рд╣реЗрдбрд░ рдХрд╛ рдЖрдХрд╛рд░ ред рдЗрд╕рд▓рд┐рдП, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рдЦрд┐рд▓рд╛рдбрд╝реА рдбреЗрдЯрд╛ рдХрд╛ рдЖрдХрд╛рд░ рдШрдЯрд╛рдХрд░ рд▓реЗ рдЬрд╛рддреЗ рд╣реИрдВ, рд╣реЗрдбрд░ рд╕реЗ рдирд╣реАрдВред

WAV рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдкрд░, рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдкреНрд░рд╛рд░реВрдк рд╕рдВрдХреБрдЪрд┐рдд рдирд╣реАрдВ рд╣реИред рдЬрдм рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рддреЛ, рдЪреАрдЬреЗрдВ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реЛрддреА рд╣реИрдВред

Ogg рдлрд╝рд╛рдЗрд▓ рдкрдврд╝реЗрдВ

WAV рдХреА рддреБрд▓рдирд╛ рдореЗрдВ Ogg рдХреА рдХреНрдпрд╛ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИ? рдпрд╣ рдПрдХ рд╕рдВрдХреБрдЪрд┐рдд рдкреНрд░рд╛рд░реВрдк рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╡рд╣рд╛рдБ рд╕реЗ рдкрд╣рд▓реЗ, рдХреИрд╕реЗ рдУрдкреНрдкрд▓ рдмрдлрд░ рдХреЛ рдбреЗрдЯрд╛ рд▓рд┐рдЦрдирд╛ рд╣реИ, рд╣рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдбреАрдХреЛрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдкрдХрдбрд╝ рдпрд╣ рд╣реИ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ Vorbis FILE рд╕реЗ рд╕реНрдЯреНрд░реАрдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЙрд▓рдмреИрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

рдХреЙрд▓рдмреИрдХ
 static size_t read_func(void* ptr, size_t size, size_t nmemb, void* datasource) { unsigned int uiBytes = Min(suiSize - suiCurrPos, (unsigned int)nmemb * (unsigned int)size); memcpy(ptr, (unsigned char*)datasource + suiCurrPos, uiBytes); suiCurrPos += uiBytes; return uiBytes; } static int seek_func(void* datasource, ogg_int64_t offset, int whence) { if (whence == SEEK_SET) suiCurrPos = (unsigned int)offset; else if (whence == SEEK_CUR) suiCurrPos = suiCurrPos + (unsigned int)offset; else if (whence == SEEK_END) suiCurrPos = suiSize; return 0; } static int close_func(void* datasource) { return 0; } static long tell_func(void* datasource) { return (long)suiCurrPos; } 



рдЕрдм рдЖрдкрдХреЛ рдкрдврд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
рдкрдврд╝рдирд╛ Ogg
 void OALOgg::getInfo(unsigned int uiOggSize, char* pvOggBuffer){ //   ov_callbacks callbacks; callbacks.read_func = &read_func; callbacks.seek_func = &seek_func; callbacks.close_func = &close_func; callbacks.tell_func = &tell_func; suiCurrPos = 0; suiSize = uiOggSize; int iRet = ov_open_callbacks(pvOggBuffer, &vf, NULL, 0, callbacks); //  vi = ov_info(&vf, -1); uiPCMSamples = (unsigned int)ov_pcm_total(&vf, -1); } void * OALOgg::ConvertOggToPCM(unsigned int uiOggSize, char* pvOggBuffer) { if(suiSize == 0){ getInfo( uiOggSize, pvOggBuffer); current_section = 0; iRead = 0; uiCurrPos = 0; } void* pvPCMBuffer = malloc(uiPCMSamples * vi->channels * sizeof(short)); //  do { iRead = ov_read(&vf, (char*)pvPCMBuffer + uiCurrPos, 4096, ┬дt_section); uiCurrPos += (unsigned int)iRead; } while (iRead != 0); return pvPCMBuffer; } void OALOgg::load(AAssetManager *mgr, const char* filename){ this->filename = filename; char* buf = 0; AAssetFile f = AAssetFile(mgr, filename); if (f.null()) { LOGE("no file %s in readOgg",filename); return ; } buf = 0; buf = (char*)malloc(f.size()); if (buf){ if(f.read(buf,f.size(),1)){ } else { free(buf); f.close(); return; } } char * data = (char *)ConvertOggToPCM(f.size(),buf); f.close(); if (vi->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; alGenBuffers(1,&buffer); alBufferData(buffer,format,data,uiPCMSamples * vi->channels * sizeof(short),vi->rate); source = 0; alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); } 



рдЬрдм рд╣рдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо C ++ рд╡рд┐рдзрд┐ loadAudio рдХрд╣рддреЗ рд╣реИрдВ, рдЬреЛ NativeCallListener рдкрд░ рд▓реЛрдб рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдзреНрд╡рдирд┐рдпреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ:
 void NativeCallListener:: load(){ oalContext = new OALContext(); //sound = new OALOgg(); sound = new OALWav(); char * fileName = new char[64]; strcpy(fileName, "audio/industrial_suspense1.wav"); //strcpy(fileName, "audio/Katatonia - Deadhouse_(piano version).ogg"); sound->load(mgr,fileName); } 

sound рдореИрдВ рдЯрд╛рдЗрдк OALSound ред рдбрдмреНрд▓реНрдпреВрдПрд╡реА рдФрд░ рдУрдЧ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореЗрд░реЗ рдкрд╛рд╕ рдХрдХреНрд╖рд╛рдПрдВ рд╣реИрдВ рдЬреЛ рдЗрд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реА рд╣реИрдВред рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рдкрджреНрдзрддрд┐ virtual void load(AAssetManager *mgr, const char* filename)= 0; рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓реЛрдб рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ virtual void load(AAssetManager *mgr, const char* filename)= 0;
рдпрд╣ рдЖрдкрдХреЛ рдзреНрд╡рдирд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХреЛ рдПрдХрдЬреБрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдирд┐рд╖реНрдХрд░реНрд╖


рдПрдХ рдмрд╛рд░ рдлрд┐рд░, рдореИрдВ рдорд╛рдлреА рдорд╛рдВрдЧрддрд╛ рд╣реВрдВ рдХрд┐ рд▓реЗрдЦ рдХрд╛рдлреА рдмрдбрд╝рд╛ рдерд╛, рдЕрдиреНрдпрдерд╛ рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред рдкреНрд░рд╕реНрддреБрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдЖрдк рдордВрдЪ рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛ рдзреНрд╡рдирд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЖрдк iOS рдФрд░ Android рдХреЗ рд▓рд┐рдП рдЧреЗрдо рдЗрдВрдЬрди рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВред

рдпрд╣рд╛рдВ рдПрдХ рдЕрддрд┐ рд╕реВрдХреНрд╖реНрдо рдЕрдВрддрд░ рд╣реИ - рдСрдбрд┐рдпреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд▓реЛрдб рд╣реИред рдЗрд╕рд▓рд┐рдП, рдзреНрд╡рдирд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдпрд╣ рд╕рдорд╛рдзрд╛рди рдорд╣рд╛рди рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрдЧреАрдд рдХреЗ рд▓рд┐рдП рдирд╣реАрдВред рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рдЕрдирдкреЗрдХреНрд╖рд┐рдд .ogg рдЧреАрдд рдХрд┐рддрдиреА рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░реЗрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рд╕реНрдЯреНрд░реАрдорд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдПрдХ рдСрдбрд┐рдпреЛ рдкреНрд▓реЗрдмреИрдХ рд▓рд┐рдЦрддрд╛ рд╣реИ, рдмрдлрд╝рд░ рдХреЗ рд▓рд┐рдП рдкреВрд░реНрдг рд▓реЛрдб рдХреЗ рдмрдЬрд╛рдпред

рд╕реНрд░реЛрдд рдХреЛрдб

рдкрд░рд┐рдпреЛрдЬрдирд╛ рдЧреНрд░рд╣рдг рдореЗрдВ рд▓рд┐рдЦреА рдЧрдИ рд╣реИред рд╕реВрддреНрд░реЛрдВ рдХреЛ рдЬреАрдердм рдкрд░ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдкреБрдирд╢реНрдЪ рдореИрдВ рдЖрд▓реЛрдЪрдирд╛ рдФрд░ рд╕рд▓рд╛рд╣ рдХреЗ рд▓рд┐рдП рддрддреНрдкрд░ рд╣реВрдВ
рдкреАрдкреАрдПрд╕ рдпрджрд┐ рдЖрдкрдХреЛ рдкрд╛рда рдореЗрдВ рд╡реНрдпрд╛рдХрд░рдг рд╕рдВрдмрдВрдзреА рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓рддреА рд╣реИрдВ, рддреЛ рджреЛрдкрд╣рд░ рдореЗрдВ рд▓рд┐рдЦрдирд╛ рдмреЗрд╣рддрд░ рд╣реИред

Source: https://habr.com/ru/post/In176559/


All Articles