@4players/odin-nodejs 0.7.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/binding.gyp CHANGED
@@ -1,61 +1,63 @@
1
1
  {
2
- "targets": [{
3
- "target_name": "odin",
4
- "sources": [
5
- "cppsrc/binding.cpp",
6
- "cppsrc/odinbindings.cpp",
7
- "cppsrc/odinclient.cpp",
8
- "cppsrc/odinroom.cpp",
9
- "cppsrc/odinmedia.cpp",
10
- "cppsrc/utilities.cpp"
11
- ],
12
- 'dependencies': [
13
- "<!(node -p \"require('node-addon-api').gyp\")"
14
- ],
15
- 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
16
- 'cflags!': [ '-fno-exceptions' ],
17
- 'cflags_cc!': [ '-fno-exceptions' ],
18
- 'conditions': [
19
- ["OS=='linux'", {
20
- 'libraries': [
21
- "<(module_root_dir)/libs/bin/linux/<(target_arch)/libodin_static.a"
22
- ],
23
- 'include_dirs': [
24
- "<!@(node -p \"require('node-addon-api').include\")",
25
- "<(module_root_dir)/libs/include"
26
- ],
27
- }],
28
- ["OS=='win'", {
29
- "defines": [
30
- "_HAS_EXCEPTIONS=1"
31
- ],
32
- "msvs_settings": {
33
- "VCCLCompilerTool": {
34
- "ExceptionHandling": 1
35
- },
36
- },
37
- 'runtime_library': [
38
- "<(module_root_dir)/libs/bin/windows/<(target_arch)/odin_static.lib"
39
- ],
40
- 'include_dirs': [
41
- "<!@(node -p \"require('node-addon-api').include\")",
42
- "<(module_root_dir)/libs/include"
43
- ],
44
- }],
45
- ["OS=='mac'", {
46
- 'xcode_settings': {
47
- 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
48
- 'CLANG_CXX_LIBRARY': 'libc++',
49
- 'MACOSX_DEPLOYMENT_TARGET': '10.12',
50
- },
51
- 'libraries': [
52
- "<(module_root_dir)/libs/bin/macos/<(target_arch)/libodin_static.a"
53
- ],
54
- 'include_dirs': [
55
- "<!@(node -p \"require('node-addon-api').include\")",
56
- "<(module_root_dir)/libs/include"
57
- ],
58
- }],
2
+ "targets": [
3
+ {
4
+ "target_name": "odin",
5
+ "sources": [
6
+ "cppsrc/binding.cpp",
7
+ "cppsrc/odinbindings.cpp",
8
+ "cppsrc/odinclient.cpp",
9
+ "cppsrc/odinroom.cpp",
10
+ "cppsrc/odinmedia.cpp",
11
+ "cppsrc/utilities.cpp"
12
+ ],
13
+ "include_dirs": [
14
+ "<!@(node -p \"require('node-addon-api').include\")",
15
+ "<(module_root_dir)/libs/include"
16
+ ],
17
+ "dependencies": [
18
+ "<!(node -p \"require('node-addon-api').gyp\")"
19
+ ],
20
+ "conditions": [
21
+ ["OS=='linux'", {
22
+ "libraries": [
23
+ "-L<(module_root_dir)/libs/bin/linux/<(target_arch)",
24
+ "-lodin_static"
59
25
  ]
60
- }]
26
+ }],
27
+ ["OS=='mac'", {
28
+ "libraries": [
29
+ "-L<(module_root_dir)/libs/bin/macos/<(target_arch)",
30
+ "-lodin_static",
31
+ ]
32
+ }],
33
+ ["OS=='win'", {
34
+ "msvs_settings": {
35
+ "VCCLCompilerTool": {
36
+ "AdditionalOptions": [ "/MD" ],
37
+ },
38
+ "VCLinkerTool": {
39
+
40
+ },
41
+ },
42
+ "libraries": [
43
+ "<(module_root_dir)/libs/bin/windows/<(target_arch)/odin_static.lib",
44
+ "-lws2_32",
45
+ "-lbcrypt",
46
+ "-lucrt",
47
+ "-lvcruntime",
48
+ "-lwinmm",
49
+ "-lntdll"
50
+ ]
51
+ }]
52
+ ],
53
+ "defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
54
+ "cflags!": [ "-fno-exceptions" ],
55
+ "cflags_cc!": [ "-fno-exceptions" ],
56
+ "xcode_settings": {
57
+ "GCC_ENABLE_CPP_EXCEPTIONS": "NO",
58
+ "CLANG_CXX_LIBRARY": "libc++",
59
+ "MACOSX_DEPLOYMENT_TARGET": "10.12",
60
+ },
61
+ }
62
+ ]
61
63
  }
@@ -72,7 +72,12 @@ OdinClient::OdinClient(const Napi::CallbackInfo& info) : Napi::ObjectWrap<OdinCl
72
72
  printf("Odin NodeJS Addon: Initializing Odin runtime (%s) with sample rate %f and %d channels\n", ODIN_VERSION, _sampleRate, _numChannels);
73
73
  #endif
74
74
 
75
- odin_startup_ex(ODIN_VERSION, _sampleRate, _numChannels == 1 ? OdinChannelLayout_Mono : OdinChannelLayout_Stereo);
75
+ // Create a OdinAudioStreamConfig struct to configure the audio stream
76
+ OdinAudioStreamConfig config;
77
+ config.sample_rate = _sampleRate;
78
+ config.channel_count = _numChannels;
79
+
80
+ odin_startup_ex(ODIN_VERSION, config);
76
81
  }
77
82
 
78
83
  /**
@@ -141,6 +146,8 @@ Napi::Value OdinClient::CreateRoom(const Napi::CallbackInfo &info) {
141
146
  if (!generator)
142
147
  {
143
148
  Napi::TypeError::New(env, "Failed to initialize token generator, invalid access key").ThrowAsJavaScriptException();
149
+ odin_token_generator_destroy(generator);
150
+ return env.Undefined();
144
151
  }
145
152
 
146
153
  /*
@@ -151,6 +158,8 @@ Napi::Value OdinClient::CreateRoom(const Napi::CallbackInfo &info) {
151
158
  if (odin_is_error(error))
152
159
  {
153
160
  Napi::TypeError::New(env, "Creating access token failed").ThrowAsJavaScriptException();
161
+ odin_token_generator_destroy(generator);
162
+ return env.Undefined();
154
163
  }
155
164
 
156
165
  /*
@@ -232,7 +232,7 @@ void OdinMedia::SendData(const Napi::CallbackInfo &info) {
232
232
  Napi::Float32Array array = info[0].As<Napi::Float32Array>();
233
233
 
234
234
  #ifdef DEBUG
235
- printf("Received %d bytes of audio data\n", (int)array.ElementLength());
235
+ printf("Sent %d bytes of audio data\n", (int)array.ElementLength());
236
236
  #endif
237
237
 
238
238
  OdinReturnCode result = odin_audio_push_data(_mediaStreamHandle, array.Data(), array.ElementLength());
@@ -331,7 +331,8 @@ Napi::Object OdinRoom::Init(Napi::Env env, Napi::Object exports) {
331
331
  Napi::Function func = DefineClass(env, "OdinRoom", {
332
332
  InstanceMethod<&OdinRoom::Join>("join", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
333
333
  InstanceMethod<&OdinRoom::UpdatePeerUserData>("updateOwnUserData", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
334
- InstanceMethod<&OdinRoom::UpdateRoomUserData>("updateRoomUserData", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
334
+ InstanceMethod<&OdinRoom::UpdatePosition>("updatePosition", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
335
+ InstanceMethod<&OdinRoom::SetPositionScale>("setPositionScale", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
335
336
  InstanceMethod<&OdinRoom::SendMessage>("sendMessage", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
336
337
  InstanceMethod<&OdinRoom::SetEventListener>("setEventListener", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
337
338
  InstanceMethod<&OdinRoom::AddEventListener>("addEventListener", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
@@ -366,6 +367,50 @@ Napi::Object OdinRoom::Init(Napi::Env env, Napi::Object exports) {
366
367
  return exports;
367
368
  }
368
369
 
370
+ /**
371
+ * Updates the position of this room. Requires x, y and z coordinates as parameters.
372
+ * @param info Napi::CallbackInfo
373
+ */
374
+ void OdinRoom::UpdatePosition(const Napi::CallbackInfo &info)
375
+ {
376
+ Napi::Env env = info.Env();
377
+
378
+ if (info.Length() != 3 || !info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber()) {
379
+ Napi::TypeError::New(env, "Provide x, y and z coordinates as numbers").ThrowAsJavaScriptException();
380
+ }
381
+
382
+ float x = info[0].ToNumber();
383
+ float y = info[1].ToNumber();
384
+ float z = info[2].ToNumber();
385
+
386
+ OdinReturnCode error = odin_room_update_position(_roomHandle, x, y, z);
387
+ if (odin_is_error(error))
388
+ {
389
+ OdinUtilities::ThrowNapiException(env, error, "Failed to update position");
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Sets the position scale for this room. Requires a scale as a parameter.
395
+ * @param info Napi::CallbackInfo
396
+ */
397
+ void OdinRoom::SetPositionScale(const Napi::CallbackInfo &info)
398
+ {
399
+ Napi::Env env = info.Env();
400
+
401
+ if (info.Length() != 1 || !info[0].IsNumber()) {
402
+ Napi::TypeError::New(env, "Provide scale as number").ThrowAsJavaScriptException();
403
+ }
404
+
405
+ float scale = info[0].ToNumber();
406
+
407
+ OdinReturnCode error = odin_room_set_position_scale(_roomHandle, scale);
408
+ if (odin_is_error(error))
409
+ {
410
+ OdinUtilities::ThrowNapiException(env, error, "Failed to set position scale");
411
+ }
412
+ }
413
+
369
414
  /**
370
415
  * Joins the Odin room. Requires a gateway URL as a parameter and optionally initial peer data.
371
416
  * @param info Napi::CallbackInfo
@@ -381,7 +426,7 @@ void OdinRoom::Join(const Napi::CallbackInfo &info) {
381
426
 
382
427
  if (info.Length() > 1) {
383
428
  Napi::Uint8Array data = info[1].As<Napi::Uint8Array>();
384
- OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Peer, data.Data(), data.ByteLength());
429
+ OdinReturnCode error = odin_room_update_peer_user_data(_roomHandle, data.Data(), data.ByteLength());
385
430
  if (odin_is_error(error))
386
431
  {
387
432
  Napi::TypeError::New(env, "Setting initial room peer data failed").ThrowAsJavaScriptException();
@@ -475,7 +520,7 @@ void OdinRoom::UpdatePeerUserData(const Napi::CallbackInfo &info) {
475
520
 
476
521
  Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
477
522
 
478
- OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Peer, data.Data(), data.ByteLength());
523
+ OdinReturnCode error = odin_room_update_peer_user_data(_roomHandle, data.Data(), data.ByteLength());
479
524
 
480
525
  if (odin_is_error(error))
481
526
  {
@@ -483,28 +528,6 @@ void OdinRoom::UpdatePeerUserData(const Napi::CallbackInfo &info) {
483
528
  }
484
529
  }
485
530
 
486
- /**
487
- * Updates the room user data. Requires an array of bytes as a parameter.
488
- * @param info
489
- * @return
490
- */
491
- void OdinRoom::UpdateRoomUserData(const Napi::CallbackInfo &info) {
492
- Napi::Env env = info.Env();
493
-
494
- if (info.Length() != 1 || !info[0].IsTypedArray()) {
495
- Napi::TypeError::New(env, "Data as byte array expected").ThrowAsJavaScriptException();
496
- }
497
-
498
- Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
499
-
500
- OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Room, data.Data(), data.ByteLength());
501
-
502
- if (odin_is_error(error))
503
- {
504
- OdinUtilities::ThrowNapiException(env, error, "Failed to update room user data");
505
- }
506
- }
507
-
508
531
  /**
509
532
  * Sends a message to the room. Requires an array of bytes as a parameter and optinally a list of peer ids to send to.
510
533
  * Please note: If the list is NULL the message will be sent to all peers in the room. If the list is not NULL the message
@@ -544,7 +567,7 @@ void OdinRoom::SendMessage(const Napi::CallbackInfo &info) {
544
567
 
545
568
  if (odin_is_error(error))
546
569
  {
547
- OdinUtilities::ThrowNapiException(env, error, "Failed to update room user data");
570
+ OdinUtilities::ThrowNapiException(env, error, "Failed to send message");
548
571
  }
549
572
  }
550
573
 
package/cppsrc/odinroom.h CHANGED
@@ -47,7 +47,6 @@ private:
47
47
  void Close(const Napi::CallbackInfo& info);
48
48
  void Join(const Napi::CallbackInfo& info);
49
49
  void UpdatePeerUserData(const Napi::CallbackInfo &info);
50
- void UpdateRoomUserData(const Napi::CallbackInfo &info);
51
50
  void SendMessage(const Napi::CallbackInfo &info);
52
51
  void SetEventListener(const Napi::CallbackInfo &info);
53
52
  void AddEventListener(const Napi::CallbackInfo &info);
@@ -57,6 +56,8 @@ private:
57
56
  EventData* PrepareEventData(OdinEvent* event);
58
57
  static uint16_t GetMediaIdFromHandle(OdinMediaStreamHandle handle);
59
58
  void HandleAudioData();
59
+ void UpdatePosition(const Napi::CallbackInfo &info);
60
+ void SetPositionScale(const Napi::CallbackInfo &info);
60
61
 
61
62
  Napi::Value CreateAudioStream(const Napi::CallbackInfo &info);
62
63
  };
Binary file
Binary file
@@ -10,23 +10,7 @@
10
10
  #include <stdint.h>
11
11
  #include <stdlib.h>
12
12
 
13
- #define ODIN_VERSION "1.4.0"
14
-
15
- #define Frame_SAMPLE_RATE 48000
16
-
17
- /**
18
- * Supported channel layouts in audio functions.
19
- */
20
- typedef enum OdinChannelLayout {
21
- /**
22
- * Samples are sequential
23
- */
24
- OdinChannelLayout_Mono,
25
- /**
26
- * Channels are interleaved
27
- */
28
- OdinChannelLayout_Stereo,
29
- } OdinChannelLayout;
13
+ #define ODIN_VERSION "1.6.4"
30
14
 
31
15
  /**
32
16
  * Known types of a media stream.
@@ -134,25 +118,11 @@ typedef enum OdinTokenAudience {
134
118
  } OdinTokenAudience;
135
119
 
136
120
  /**
137
- * Supported targets for user data updates.
138
- */
139
- typedef enum OdinUserDataTarget {
140
- /**
141
- * Individual user data for your own peer
142
- */
143
- OdinUserDataTarget_Peer,
144
- /**
145
- * Global user data for the room
146
- */
147
- OdinUserDataTarget_Room,
148
- } OdinUserDataTarget;
149
-
150
- /**
151
- * A pointer to a local ODIN token generator used to generate signed room tokens based based on an
152
- * access key. Please note, that access keys are your the unique authentication keys to be used to
153
- * generate room tokens for accessing the ODIN server network. For your own security, we strongly
154
- * recommend that you _NEVER_ put an access key in your client code and generate room tokens on a
155
- * server.
121
+ * A pointer to a local ODIN token generator, employed for generating signed room tokens predicated
122
+ * on an access key. Be aware that access keys serve as your unique authentication keys, requisite
123
+ * for generating room tokens to access the ODIN server network. To ensure your security, it's
124
+ * strongly recommended that you _NEVER_ embed an access key within your client code, and instead
125
+ * generate room tokens on a server.
156
126
  */
157
127
  typedef struct OdinTokenGenerator OdinTokenGenerator;
158
128
 
@@ -164,6 +134,20 @@ typedef struct OdinTokenGenerator OdinTokenGenerator;
164
134
  */
165
135
  typedef uint32_t OdinReturnCode;
166
136
 
137
+ /**
138
+ * Audio stream configuration.
139
+ */
140
+ typedef struct OdinAudioStreamConfig {
141
+ /**
142
+ * The number of samples per second in hertz (between 8000 and 192000)
143
+ */
144
+ uint32_t sample_rate;
145
+ /**
146
+ * The number of channels for the new audio stream (between 1 and 2)
147
+ */
148
+ uint8_t channel_count;
149
+ } OdinAudioStreamConfig;
150
+
167
151
  /**
168
152
  * Internal handle identifier for an ODIN room to interact with.
169
153
  */
@@ -491,20 +475,6 @@ typedef struct OdinApmConfig {
491
475
  bool gain_controller;
492
476
  } OdinApmConfig;
493
477
 
494
- /**
495
- * Audio stream configuration.
496
- */
497
- typedef struct OdinAudioStreamConfig {
498
- /**
499
- * The number of samples per second in hertz (between 8000 and 192000)
500
- */
501
- uint32_t sample_rate;
502
- /**
503
- * The number of channels for the new audio stream (between 1 and 2)
504
- */
505
- uint8_t channel_count;
506
- } OdinAudioStreamConfig;
507
-
508
478
  /**
509
479
  * Audio stream statistics.
510
480
  */
@@ -583,30 +553,30 @@ size_t odin_error_format(OdinReturnCode error, char *buf, size_t buf_len);
583
553
  bool odin_is_error(OdinReturnCode code);
584
554
 
585
555
  /**
586
- * Starts the internal ODIN client runtime using recommended settings for audio output and verifies
587
- * that the correct API header file is used. This is ref-counted so you need matching calls of startup
588
- * and shutdown in your application. A lot of the functions in the API require a running ODIN runtime.
589
- * With the only exception being the `access_key` and `token_generator` related functions.
556
+ * Initializes the internal ODIN client runtime with optimized settings for audio output, ensuring
557
+ * the correct API header file is employed. This operation is ref-counted, necessitating paired
558
+ * invocations of startup and shutdown within your application. The majority of the API functions
559
+ * hinge on an active ODIN runtime, with the sole exception of `access_key` and `token_generator`
560
+ * related functions.
590
561
  *
591
- * Note: Use `ODIN_VERSION` to pass the `version` argument.
562
+ * Note: Utilize `ODIN_VERSION` to supply the `version` argument.
592
563
  */
593
564
  bool odin_startup(const char *version);
594
565
 
595
566
  /**
596
- * Starts the internal ODIN client runtime and allows passing the sample rate and channel layout
597
- * for audio output. This is ref-counted so you need matching calls of startup and shutdown in your
598
- * application.
567
+ * Initializes the internal ODIN client runtime, permitting the specification of sample rate and
568
+ * channel layout for audio output. This operation is ref-counted, necessitating paired invocations
569
+ * of startup and shutdown within your application.
599
570
  *
600
- * Note: Make sure to use the same settings on consecutive calls of this function.
571
+ * Note: Ensure consistent settings are used on successive invocations of this function.
601
572
  */
602
- bool odin_startup_ex(const char *version,
603
- uint32_t output_sample_rate,
604
- enum OdinChannelLayout output_channel_layout);
573
+ bool odin_startup_ex(const char *version, struct OdinAudioStreamConfig output_config);
605
574
 
606
575
  /**
607
- * Terminates the internal ODIN runtime. This function _should_ be called before shutting down
608
- * the application. After calling this function all `odin_*` methods will fail immediately.
609
- * (Given the internal ref-count reached zero. See `odin_startup` for more information)
576
+ * Shuts down the internal ODIN runtime. It is advisable to invoke this function prior to
577
+ * terminating the application. Post invocation, all `odin_*` methods will cease to function
578
+ * immediately, provided the internal ref-count has descended to zero. Refer to `odin_startup`
579
+ * for additional details.
610
580
  */
611
581
  void odin_shutdown(void);
612
582
 
@@ -639,13 +609,13 @@ OdinReturnCode odin_room_set_event_callback(OdinRoomHandle room,
639
609
  void *extra_data);
640
610
 
641
611
  /**
642
- * Sets the scaling used for all coordinates passed to `odin_room_update_position`. This allows
643
- * adapting to the individual needs of your game coordinate system if necessary. Only peers within
644
- * a unit circle with a radius of `1.0` are able to 'see' each other. When changing the position
645
- * of a peer, the position must be scaled such as that the maximum distance is one or less. The
646
- * scaling can be done either manually or by setting the multiplicative scale here.
612
+ * Sets the scaling factor for coordinates supplied to `odin_room_update_position`, facilitating
613
+ * adaptation to your game's unique coordinate system requirements. Peers are visible to each other
614
+ * only within a unit circle of radius `1.0`. When altering a peer's position, ensure the position
615
+ * is scaled such that the maximum distance remains one or less. This scaling can be performed
616
+ * manually or by specifying the multiplicative scale here.
647
617
  *
648
- * Note: Please make sure that all of your client apps use the same scaling.
618
+ * Note: It's crucial to maintain consistent scaling across all client applications.
649
619
  */
650
620
  OdinReturnCode odin_room_set_position_scale(OdinRoomHandle room, float scale);
651
621
 
@@ -679,28 +649,26 @@ OdinReturnCode odin_room_peer_id(OdinRoomHandle room, uint64_t *out_peer_id);
679
649
  OdinReturnCode odin_room_connection_stats(OdinRoomHandle room, struct OdinConnectionStats *stats);
680
650
 
681
651
  /**
682
- * Updates the custom user data for either your own peer or the specified `OdinRoomHandle` itself.
683
- * All user data is synced automatically, which allows storing of arbitrary information for each
684
- * individual peer and even globally for the room if needed.
652
+ * Updates the custom user data for your own peer. All user data is synced automatically, which
653
+ * allows storing of arbitrary information for each individual peer.
685
654
  *
686
655
  * Note: Use this before calling `odin_room_join` to set initial peer user data upon connect.
687
656
  */
688
- OdinReturnCode odin_room_update_user_data(OdinRoomHandle room,
689
- enum OdinUserDataTarget target,
690
- const uint8_t *user_data,
691
- size_t user_data_length);
657
+ OdinReturnCode odin_room_update_peer_user_data(OdinRoomHandle room,
658
+ const uint8_t *user_data,
659
+ size_t user_data_length);
692
660
 
693
661
  /**
694
- * Updates the two-dimensional position of your own peer in the given `OdinRoomHandle`. The server
695
- * will use the specified coordinates for each peer in the same room to apply automatic culling
696
- * based on unit circles with a radius of `1.0`. This is ideal for any scenario, where you want to
697
- * put a very large number of peers into the same room and make them only 'see' each other while
698
- * being in proximity. Additionally, you can use `odin_room_set_position_scale` to adjust the
699
- * distance multiplier for position updates if needed.
662
+ * Updates the three-dimensional position of the current peer within the specified `OdinRoomHandle`.
663
+ * The server utilizes the provided coordinates to perform automatic culling among peers in the same
664
+ * room, based on unit circles with a radius of `1.0`. This feature is particularly beneficial in
665
+ * scenarios involving a large number of peers within the same room, enabling peers to interact or
666
+ * 'see' each other only when in close proximity. To modify the distance sensitivity for position
667
+ * updates, use `odin_room_set_position_scale`.
700
668
  *
701
669
  * Note: Use this before calling `odin_room_join` to set the initial peer position upon connect.
702
670
  */
703
- OdinReturnCode odin_room_update_position(OdinRoomHandle room, float x, float y);
671
+ OdinReturnCode odin_room_update_position(OdinRoomHandle room, float x, float y, float z);
704
672
 
705
673
  /**
706
674
  * Sends arbitrary data to a list of target peers over the ODIN server. If `NULL` is specified, the
@@ -725,12 +693,12 @@ OdinReturnCode odin_room_add_media(OdinRoomHandle room, OdinMediaStreamHandle me
725
693
  OdinReturnCode odin_room_configure_apm(OdinRoomHandle room, struct OdinApmConfig config);
726
694
 
727
695
  /**
728
- * Creates a new audio stream, which can be added to a room and send data over it.
696
+ * Creates a new audio input stream, which can be added to a room and send data over it.
729
697
  */
730
698
  OdinMediaStreamHandle odin_audio_stream_create(struct OdinAudioStreamConfig config);
731
699
 
732
700
  /**
733
- * Creates a new video stream, which can be added to a room and send data over it.
701
+ * Creates a new video input stream, which can be added to a room and send data over it.
734
702
  *
735
703
  * Note: Video streams are not supported yet.
736
704
  */
@@ -760,21 +728,45 @@ OdinReturnCode odin_media_stream_peer_id(OdinMediaStreamHandle stream, uint64_t
760
728
  */
761
729
  enum OdinMediaStreamType odin_media_stream_type(OdinMediaStreamHandle stream);
762
730
 
731
+ /**
732
+ * Instructs the server to pause the specified `OdinMediaStreamHandle`, ceasing the reception of
733
+ * data. This operation essentially communicates a server-side mute request from the client, thus
734
+ * indicating a desire to halt packet reception for this media stream.
735
+ */
736
+ OdinReturnCode odin_media_stream_pause(OdinMediaStreamHandle stream);
737
+
738
+ /**
739
+ * Instructs the server to resume the specified output `OdinMediaStreamHandle`, re-initiating the
740
+ * reception of data. This operation essentially communicates a server-side unmute request from the
741
+ * client, indicating a desire to restart packet reception for this media stream.
742
+ */
743
+ OdinReturnCode odin_media_stream_resume(OdinMediaStreamHandle stream);
744
+
763
745
  /**
764
746
  * Sends data to the audio stream. The data has to be interleaved [-1, 1] float data.
765
747
  */
766
748
  OdinReturnCode odin_audio_push_data(OdinMediaStreamHandle stream, const float *buf, size_t buf_len);
767
749
 
768
750
  /**
769
- * Reads audio data from the specified `OdinMediaStreamHandle`. This will return audio data in
770
- * 48kHz interleaved.
771
- *
772
- * Note: `out_channel_layout` is reserved for future use.
751
+ * Reads audio data from the specified `OdinMediaStreamHandle`. This will return audio data in the
752
+ * format specified when calling `odin_startup_ex` or 48 kHz interleaved by default.
773
753
  */
774
754
  OdinReturnCode odin_audio_read_data(OdinMediaStreamHandle stream,
775
755
  float *out_buffer,
776
756
  size_t out_buffer_len);
777
757
 
758
+ /**
759
+ * Returns the number of samples available in the audio buffer of an output `OdinMediaStreamHandle`.
760
+ */
761
+ OdinReturnCode odin_audio_data_len(OdinMediaStreamHandle stream);
762
+
763
+ /**
764
+ * Resets the specified `OdinMediaStreamHandle` to its initial state, restoring it to its default
765
+ * configuration. This operation resets the internal Opus encoder/decoder, ensuring a clean state.
766
+ * Additionally, it clears internal buffers, providing a fresh start.
767
+ */
768
+ OdinReturnCode odin_audio_reset(OdinMediaStreamHandle stream);
769
+
778
770
  /**
779
771
  * Retrieves statistics for the specified `OdinMediaStreamHandle`.
780
772
  *
@@ -784,9 +776,9 @@ OdinReturnCode odin_audio_stats(OdinMediaStreamHandle stream, struct OdinAudioSt
784
776
 
785
777
  /**
786
778
  * Reads up to `out_buffer_len` samples from the given streams and mixes them into the `out_buffer`.
787
- * All audio streams will be read based on a 48khz sample rate so make sure to allocate the buffer
788
- * accordingly. After the call the `out_buffer_len` will contain the amount of samples that have
789
- * actually been read and mixed into `out_buffer`.
779
+ * All audio streams will be read based on the sample rate you chose when initializing the ODIN runtime
780
+ * so make sure to allocate the buffer accordingly. After the call the `out_buffer_len` will contain
781
+ * the amount of samples that have actually been read and mixed into `out_buffer`.
790
782
  *
791
783
  * If enabled this will also apply any audio processing to the output stream and feed back required
792
784
  * data to the internal audio processing pipeline which requires a final mix.
@@ -803,6 +795,17 @@ OdinReturnCode odin_audio_mix_streams(OdinRoomHandle room,
803
795
  */
804
796
  OdinReturnCode odin_audio_process_reverse(OdinRoomHandle room, float *buffer, size_t buffer_len);
805
797
 
798
+ /**
799
+ * Sets the delay estimate for the reverse stream used in the ODIN echo cancellation. This function
800
+ * is important in scenarios where the audio output and the audio input are not synchronized. An
801
+ * accurate delay value ensures that the echo canceller can correctly align the two audio streams,
802
+ * resulting in effective echo cancellation.
803
+ *
804
+ * Improper delay values may lead to poor echo cancellation and thus degrade the quality of the
805
+ * audio communication.
806
+ */
807
+ OdinReturnCode odin_audio_set_stream_delay(OdinRoomHandle room, uint64_t delay_ms);
808
+
806
809
  /**
807
810
  * Creates a new ODIN resampler instance. This is intended for situations where your audio pipeline
808
811
  * doesn't support 48 kHz.
@@ -834,28 +837,29 @@ OdinReturnCode odin_resampler_process(OdinResamplerHandle resampler,
834
837
  OdinReturnCode odin_resampler_destroy(OdinResamplerHandle resampler);
835
838
 
836
839
  /**
837
- * Creates a new access key required to access the ODIN network. An access key is a 44 character
838
- * long Base64-String, which consists of a version, random bytes and a checksum.
840
+ * Creates a new access key crucial for signing tokens, facilitating access to an ODIN server. An
841
+ * access key is a 44-character long Base64 String, embodying a version identifier, random bytes,
842
+ * and a checksum.
839
843
  */
840
844
  OdinReturnCode odin_access_key_generate(char *buf, size_t buf_len);
841
845
 
842
846
  /**
843
- * Retrieves the key ID from a specified access key. The key ID is included in room tokens,
844
- * making it possible to identify which public key must be used for verification.
847
+ * Extracts the key ID from a specified access key. The key ID is embedded in room tokens, enabling
848
+ * the identification of the corresponding public key required for verification.
845
849
  */
846
850
  OdinReturnCode odin_access_key_id(const char *access_key, char *out_key_id, size_t out_key_id_len);
847
851
 
848
852
  /**
849
- * Retrieves the public key from a specified access key. The public key is based on the Ed25519
850
- * curve and must be submitted to _4Players_ so that a generated room token can be verified.
853
+ * Extracts the public key from a specified access key. The public key, derived from the Ed25519
854
+ * curve, must be shared with _4Players_ to enable verification of a generated room token.
851
855
  */
852
856
  OdinReturnCode odin_access_key_public_key(const char *access_key,
853
857
  char *out_public_key,
854
858
  size_t out_public_key_len);
855
859
 
856
860
  /**
857
- * Retrieves the secret key from a specified access key. The secret key is based on the Ed25519
858
- * curve and used to sign a generated room token to access the ODIN network.
861
+ * Extracts the private key from a specified access key. The private key, rooted in the Ed25519
862
+ * curve, is utilized to sign a generated room token for accessing the ODIN network.
859
863
  */
860
864
  OdinReturnCode odin_access_key_secret_key(const char *access_key,
861
865
  char *out_secret_key,
package/odin.media.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {OdinRoom} from "./odin.room";
1
+ import {OdinAPMSettings, OdinRoom} from "./odin.room";
2
2
 
3
3
  /**
4
4
  * The OdinMedia class. Represents a local media stream added to the room - i.e. a microphone, another audio stream like files.
@@ -10,8 +10,9 @@ export declare class OdinMedia {
10
10
  * @param room - The room to add the media to.
11
11
  * @param sampleRate - The sample rate of the audio stream (between 8000 and 48000)
12
12
  * @param channelCount - The number of channels of the audio stream (1 or 2)
13
+ * @param options - Optional configuration options for Odin Audio Processing Module (APM).
13
14
  */
14
- constructor(room: OdinRoom, sampleRate: number, channelCount: number);
15
+ constructor(room: OdinRoom, sampleRate: number, channelCount: number, options?: OdinAPMSettings);
15
16
 
16
17
  /**
17
18
  * Closes the local audio stream and removed the media from the room
package/odin.room.d.ts CHANGED
@@ -446,10 +446,32 @@ export declare class OdinRoom {
446
446
  updateOwnUserData(userData: Uint8Array): void;
447
447
 
448
448
  /**
449
- * Updates the room user data (for all peers)
450
- * @param userData - The new user data to set.
451
- */
452
- updateRoomUserData(userData: Uint8Array): void;
449
+ * Updates the three-dimensional position of the current peer in this room.
450
+ * The server utilizes the provided coordinates to perform automatic culling among peers in the same
451
+ * room, based on unit circles with a radius of `1.0`. This feature is particularly beneficial in
452
+ * scenarios involving a large number of peers within the same room, enabling peers to interact or
453
+ * 'see' each other only when in close proximity. To modify the distance sensitivity for position
454
+ * updates, use `setPositionScale`.
455
+ *
456
+ * Note: Use this before calling `join` to set the initial peer position upon connect.
457
+ *
458
+ * @param x - The new x position of the peer.
459
+ * @param y - The new y position of the peer.
460
+ * @param z - The new z position of the peer.
461
+ */
462
+ updatePosition(x: number, y: number, z: number): void;
463
+
464
+ /**
465
+ * Sets the scaling factor for coordinates supplied to `updatePosition`, facilitating
466
+ * adaptation to your game's unique coordinate system requirements. Peers are visible to each other
467
+ * only within a unit circle of radius `1.0`. When altering a peer's position, ensure the position
468
+ * is scaled such that the maximum distance remains one or less. This scaling can be performed
469
+ * manually or by specifying the multiplicative scale here.
470
+ *
471
+ * Note: It's crucial to maintain consistent scaling across all client applications.
472
+ * @param scale - The new scaling factor to use.
473
+ */
474
+ setPositionScale(scale: number);
453
475
 
454
476
  /**
455
477
  * Closes the room and disconnects from the server.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@4players/odin-nodejs",
3
- "version": "0.7.4",
4
- "description": "",
3
+ "version": "0.9.0",
4
+ "description": "NodeJS bindings for the ODIN SDK. Use for AI enhanced human interactions, content moderation and audio processing features in a backend.",
5
5
  "main": "index.cjs",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
Binary file
@@ -21,7 +21,7 @@ const userData = {
21
21
  version: "0.1"
22
22
  }
23
23
  const data = new TextEncoder().encode(JSON.stringify(userData));
24
- const odinClient = new OdinClient(accessKey, 44100, 1);
24
+ const odinClient = new OdinClient(accessKey, 48000, 2);
25
25
  const room = odinClient.createRoom(roomName, userName);
26
26
 
27
27
  // Join the room
@@ -30,9 +30,7 @@ room.join("gateway.odin.4players.io", data);
30
30
  // Send a message to the room
31
31
  const message = {
32
32
  kind: 'message',
33
- payload: {
34
- text: 'Hello, I am a music bot and will stream some music to you.'
35
- }
33
+ payload: 'Hello, I am a music bot and will stream some music to you.'
36
34
  }
37
35
  room.sendMessage(new TextEncoder().encode(JSON.stringify(message)));
38
36
 
@@ -41,29 +39,48 @@ const sendMusic = async (media) => {
41
39
  // Prepare our MP3 decoder and load the sample file
42
40
  const audioBuffer = await decode(fs.readFileSync('./santa.mp3'));
43
41
 
44
- // Print our some info about the audio file
45
- console.log(audioBuffer);
46
-
47
42
  // Create a stream that will match the settings of the file
48
- const audioBufferStream = new AudioBufferStream({channels: 1, sampleRate: 44100, float: true, bitDepth: 32});
43
+ const audioBufferStream = new AudioBufferStream({
44
+ channels: audioBuffer.numberOfChannels,
45
+ sampleRate: audioBuffer.sampleRate,
46
+ float: true,
47
+ bitDepth: 32,
48
+ chunkLength: 960 // 960 bytes every 20ms - might be doubled (1920) depending on the sample rate
49
+ });
49
50
 
50
- // Whenever the stream has data, send it to the media stream
51
+ // Create a queue to store the chunks of audio data
52
+ const queue = [];
53
+
54
+ // Whenever the stream has data, add it to the queue
51
55
  audioBufferStream.on('data', (data) => {
52
- const floats = new Float32Array(new Uint8Array(data).buffer)
53
- media.sendAudioData(floats);
56
+ const floats = new Float32Array(new Uint8Array(data).buffer);
57
+ queue.push(floats);
54
58
  });
55
59
 
60
+ // Start a timer to send audio data at regular intervals
61
+ const interval = setInterval(() => {
62
+ if (queue.length > 0) {
63
+ const chunk = queue.shift();
64
+ media.sendAudioData(chunk);
65
+ } else {
66
+ // If there's no more data to send, stop the timer
67
+ clearInterval(interval);
68
+ audioBufferStream.end();
69
+ console.log("Audio finished");
70
+ }
71
+ }, 20); // Send a chunk every 20ms
72
+
56
73
  audioBufferStream.write(audioBuffer);
57
74
  }
58
75
 
59
76
  // Create a media stream in the room - it will return an OdinMedia instance that we can use to send data to ODIN
60
- const media = room.createAudioStream(44100, 1);
77
+ const media = room.createAudioStream(48000, 2);
61
78
  console.log(media);
62
79
  console.log("MEDIA-ID:", media.id);
63
80
 
64
81
  // Start the stream and send the music to ODIN
65
82
  sendMusic(media).then(() => {
66
- console.log("Finished sending song");
83
+ console.log("Started sending audio");
67
84
  });
68
85
 
69
86
  // Wait until the user presses a key to stop
Binary file