@@ -71,183 +71,224 @@ All three libraries talk to the same Android system services, but through differ
7171- ** Android NDK r28** (28.0.13004108) or later
7272- ** API level 35** (Android 15) target
7373
74- ## Usage Examples
74+ ## Examples
7575
76- ### Audio Playback (AAudio)
76+ All types implement idempotent, nil-safe ` Close() error ` . Error types wrap NDK status codes and work with ` errors.Is ` .
7777
78- Configure a stream with the fluent builder, write samples, and clean up:
78+ <details >
79+ <summary >Audio playback (AAudio)</summary >
7980
8081``` go
81- import " github.com/AndroidGoLab/ndk/audio"
82-
83- builder , err := audio.NewStreamBuilder ()
84- if err != nil {
85- log.Fatal (err)
86- }
87- defer builder.Close ()
88-
89- builder.
90- SetDirection (audio.Output ).
91- SetSampleRate (44100 ).
92- SetChannelCount (2 ).
93- SetFormat (audio.PcmFloat ).
94- SetPerformanceMode (audio.LowLatency ).
95- SetSharingMode (audio.Shared )
96-
97- stream , err := builder.Open ()
98- if err != nil {
99- log.Fatal (err)
100- }
101- defer stream.Close ()
102-
103- log.Printf (" opened: %d Hz, %d ch, burst=%d " ,
104- stream.SampleRate (), stream.ChannelCount (), stream.FramesPerBurst ())
105-
106- stream.Start ()
107- defer stream.Stop ()
108-
109- buf := make ([]float32 , int (stream.FramesPerBurst ())*2 )
110- stream.Write (unsafe.Pointer (&buf[0 ]), stream.FramesPerBurst (), 1_000_000_000)
111- ```
82+ package main
11283
113- ### Camera Discovery
84+ import (
85+ " log"
86+ " unsafe"
11487
115- List cameras and query capabilities through the Camera2 NDK API:
88+ " github.com/AndroidGoLab/ndk/audio"
89+ )
11690
117- ``` go
118- import " github.com/AndroidGoLab/ndk/camera"
91+ func main () {
92+ builder , err := audio.NewStreamBuilder ()
93+ if err != nil {
94+ log.Fatal (err)
95+ }
96+ defer builder.Close ()
11997
120- mgr := camera.NewManager ()
121- defer mgr.Close ()
98+ builder.
99+ SetDirection (audio.Output ).
100+ SetSampleRate (44100 ).
101+ SetChannelCount (2 ).
102+ SetFormat (audio.PcmFloat ).
103+ SetPerformanceMode (audio.LowLatency ).
104+ SetSharingMode (audio.Shared )
122105
123- ids , err := mgr.CameraIdList ()
124- if err != nil {
125- log.Fatal (err) // camera.ErrPermissionDenied if CAMERA not granted
126- }
106+ stream , err := builder.Open ()
107+ if err != nil {
108+ log.Fatal (err)
109+ }
110+ defer stream.Close ()
111+
112+ log.Printf (" opened: %d Hz, %d ch, burst=%d " ,
113+ stream.SampleRate (), stream.ChannelCount (), stream.FramesPerBurst ())
114+
115+ if err := stream.Start (); err != nil {
116+ log.Fatal (err)
117+ }
118+ defer stream.Stop ()
127119
128- for _ , id := range ids {
129- meta , _ := mgr.GetCameraCharacteristics (id)
130- orientation := meta.I32At (uint32 (camera.SensorOrientation ), 0 )
131- log.Printf (" camera %s : orientation=%d °" , id, orientation)
132- }
120+ buf := make ([]float32 , int (stream.FramesPerBurst ())*2 )
121+ stream.Write (unsafe.Pointer (&buf[0 ]), stream.FramesPerBurst (), 1_000_000_000)
122+ }
133123```
134124
135- ### Sensor Querying
125+ </ details >
136126
137- Discover device sensors through the singleton sensor manager:
127+ <details >
128+ <summary >Camera discovery</summary >
138129
139130``` go
140- import " github.com/AndroidGoLab/ndk/sensor "
131+ package main
141132
142- mgr := sensor. GetInstance ()
143- accel := mgr. DefaultSensor (sensor. Accelerometer )
133+ import (
134+ " log "
144135
145- fmt.Printf (" Sensor: %s (%s )\n " , accel.Name (), accel.Vendor ())
146- fmt.Printf (" Resolution: %g , min delay: %d µs\n " ,
147- accel.Resolution (), accel.MinDelay ())
136+ " github.com/AndroidGoLab/ndk/camera"
137+ )
138+
139+ func main () {
140+ mgr := camera.NewManager ()
141+ defer mgr.Close ()
142+
143+ ids , err := mgr.CameraIdList ()
144+ if err != nil {
145+ log.Fatal (err) // camera.ErrPermissionDenied if CAMERA not granted
146+ }
147+
148+ for _ , id := range ids {
149+ meta , _ := mgr.GetCameraCharacteristics (id)
150+ orientation := meta.I32At (uint32 (camera.SensorOrientation ), 0 )
151+ log.Printf (" camera %s : orientation=%d °" , id, orientation)
152+ }
153+ }
148154```
149155
150- ### Event Loop (ALooper)
156+ </ details >
151157
152- Prepare a thread-local looper and poll for events:
158+ <details >
159+ <summary >Sensor querying</summary >
153160
154161``` go
155- import " github.com/AndroidGoLab/ndk/looper"
156-
157- runtime.LockOSThread ()
158- defer runtime.UnlockOSThread ()
159-
160- lp := looper.Prepare (1 ) // ALOOPER_PREPARE_ALLOW_NON_CALLBACKS
161- defer lp.Close ()
162-
163- go func () {
164- time.Sleep (100 * time.Millisecond )
165- lp.Acquire ()
166- lp.Wake ()
167- }()
168-
169- var fd , events int32
170- var data unsafe.Pointer
171- switch looper.PollOnce (-1 , &fd, &events, &data) {
172- case -1 : // ALOOPER_POLL_WAKE
173- log.Println (" woke up" )
174- case -3 : // ALOOPER_POLL_TIMEOUT
175- log.Println (" timed out" )
176- }
162+ package main
163+
164+ import (
165+ " fmt"
166+
167+ " github.com/AndroidGoLab/ndk/sensor"
168+ )
169+
170+ func main () {
171+ mgr := sensor.GetInstance ()
172+ accel := mgr.DefaultSensor (sensor.Accelerometer )
173+
174+ fmt.Printf (" Sensor: %s (%s )\n " , accel.Name (), accel.Vendor ())
175+ fmt.Printf (" Resolution: %g , min delay: %d µs\n " ,
176+ accel.Resolution (), accel.MinDelay ())
177+ }
177178```
178179
179- ### Camera Preview (Full Pipeline)
180+ </ details >
180181
181- A complete camera-to-screen example using NativeActivity, EGL, and OpenGL ES:
182+ <details >
183+ <summary >Event loop (ALooper)</summary >
182184
183185``` go
186+ package main
187+
184188import (
185- " github.com/AndroidGoLab/ndk/activity "
186- " github.com/AndroidGoLab/ndk/camera "
187- " github.com/AndroidGoLab/ndk/egl "
188- " github.com/AndroidGoLab/ndk/gles2 "
189- " github.com/AndroidGoLab/ndk/surfacetexture "
190- " github.com/AndroidGoLab/ndk/window "
189+ " log "
190+ " runtime "
191+ " time "
192+ " unsafe "
193+
194+ " github.com/AndroidGoLab/ndk/looper "
191195)
192196
193- // 1. Open camera
194- mgr := camera.NewManager ()
195- defer mgr.Close ()
196-
197- device , err := mgr.OpenCamera (cameraID, camera.DeviceStateCallbacks {
198- OnDisconnected : func () { log.Println (" disconnected" ) },
199- OnError : func (code int ) { log.Printf (" error: %d " , code) },
200- })
201- defer device.Close ()
202-
203- // 2. Create capture request
204- request , _ := device.CreateCaptureRequest (camera.Preview )
205- defer request.Close ()
206-
207- // 3. Wire output surfaces
208- target , _ := camera.NewOutputTarget (nativeWindow)
209- request.AddTarget (target)
210-
211- container , _ := camera.NewSessionOutputContainer ()
212- output , _ := camera.NewSessionOutput (nativeWindow)
213- container.Add (output)
214-
215- // 4. Start capture
216- session , _ := device.CreateCaptureSession (container,
217- camera.SessionStateCallbacks {
218- OnReady : func () { log.Println (" ready" ) },
219- OnActive : func () { log.Println (" active" ) },
220- })
221- session.SetRepeatingRequest (request)
222-
223- // 5. Cleanup (reverse order)
224- defer session.Close ()
225- defer container.Close ()
226- defer output.Close ()
227- defer target.Close ()
197+ func main () {
198+ runtime.LockOSThread ()
199+ defer runtime.UnlockOSThread ()
200+
201+ lp := looper.Prepare (int32 (looper.ALOOPER_PREPARE_ALLOW_NON_CALLBACKS ))
202+ defer func () { _ = lp.Close () }()
203+
204+ lp.Acquire ()
205+ go func () {
206+ time.Sleep (100 * time.Millisecond )
207+ lp.Wake ()
208+ }()
209+
210+ var fd , events int32
211+ var data unsafe.Pointer
212+ result := looper.LOOPER_POLL (looper.PollOnce (-1 , &fd, &events, &data))
213+
214+ switch result {
215+ case looper.ALOOPER_POLL_WAKE :
216+ log.Println (" woke up" )
217+ case looper.ALOOPER_POLL_TIMEOUT :
218+ log.Println (" timed out" )
219+ }
220+ }
228221```
229222
230- See [ ` examples/camera/display/ ` ] ( examples/camera/display/ ) for the complete working application with EGL rendering and permission handling. Build it with ` make apk-displaycamera ` .
223+ </ details >
231224
232- ### Asset Loading
225+ <details >
226+ <summary >Camera preview (full pipeline)</summary >
233227
234- Read files from the APK's ` assets/ ` directory:
228+ A complete camera-to-screen example using NativeActivity, EGL, and OpenGL ES. See [ ` examples/camera/display/ ` ] ( examples/camera/display/ ) for the full working application. Build it with ` make apk-displaycamera ` .
235229
236230``` go
237- import " github.com/AndroidGoLab/ndk/asset"
231+ // Sketch of the camera pipeline (requires NativeActivity context)
232+
233+ mgr := camera.NewManager ()
234+ defer mgr.Close ()
238235
239- // mgr obtained from activity.AssetManager
240- a := mgr.Open (" textures/wood.png" , asset.Streaming )
241- defer a.Close ()
236+ device , err := mgr.OpenCamera (cameraID, camera.DeviceStateCallbacks {
237+ OnDisconnected : func () { log.Println (" disconnected" ) },
238+ OnError : func (code int ) { log.Printf (" error: %d " , code) },
239+ })
240+ defer device.Close ()
242241
243- size := a.Length ()
244- buf := make ([]byte , size)
245- a.Read (buf)
242+ request , _ := device.CreateCaptureRequest (camera.Preview )
243+ defer request.Close ()
244+
245+ target , _ := camera.NewOutputTarget (nativeWindow)
246+ request.AddTarget (target)
247+
248+ container , _ := camera.NewSessionOutputContainer ()
249+ output , _ := camera.NewSessionOutput (nativeWindow)
250+ container.Add (output)
251+
252+ session , _ := device.CreateCaptureSession (container,
253+ camera.SessionStateCallbacks {
254+ OnReady : func () { log.Println (" ready" ) },
255+ OnActive : func () { log.Println (" active" ) },
256+ })
257+ session.SetRepeatingRequest (request)
246258```
247259
248- All types implement idempotent, nil-safe ` Close() error ` . Error types wrap NDK status codes and work with ` errors.Is ` .
260+ </ details >
249261
250- ### Other examples
262+ <details >
263+ <summary >Asset loading</summary >
264+
265+ ``` go
266+ package main
267+
268+ import (
269+ " fmt"
270+ " io"
271+ " unsafe"
272+
273+ " github.com/AndroidGoLab/ndk/asset"
274+ )
275+
276+ func main () {
277+ // mgr obtained from activity.AssetManager in a real NativeActivity app.
278+ // This example documents the API pattern.
279+ var mgr *asset.Manager // = activity.AssetManager(nativeActivity)
280+
281+ a := mgr.Open (" textures/wood.png" , asset.Streaming )
282+ defer a.Close ()
283+
284+ size := a.Length ()
285+ buf := make ([]byte , size)
286+ _, _ = io.ReadFull (unsafe.NewReader (a), buf)
287+ fmt.Printf (" read %d bytes\n " , len (buf))
288+ }
289+ ```
290+
291+ </details >
251292
252293<details >
253294<summary >How to record from the microphone</summary >
@@ -849,9 +890,7 @@ func main() {
849890
850891</details >
851892
852- ### More examples
853-
854- For more examples, see: [ ` examples/ ` ] ( examples/ ) .
893+ For more examples, see [ ` examples/ ` ] ( examples/ ) .
855894
856895## ndkcli
857896
0 commit comments